2

I have this very old Android project that I haven't touched for a long while. It stores some user data on the users Google Drive appdata folder. Now I'm updating the app to a Flutter version and since Google Drive API is being deprecated, there's no plugin for Flutter, I believe I need to use googleapi for that now. But I can't find much regarding my problem for flutter. I got to the point of signing in with google_sign_in: ^4.0.7

GoogleSignIn _googleSignIn = GoogleSignIn(
    scopes: [
      'email',
      'https://www.googleapis.com/auth/drive.appdata',
      'https://www.googleapis.com/auth/drive.file',
    ],
  );
  try {
    GoogleSignInAccount account = await _googleSignIn.signIn();
  } catch (error) {
    print(error);
  }

That works fine, but I got stuck there. How can I go from there and read a file inside the appdata folder on the user's Google Drive?

EDIT1: This answer helped, I managed to get the httpClient but I'm still stuck on how to get the appdata folder and its files How to use Google API in flutter?

It seems that googleapi doesn't support the appfolder since Google MAY be deprecating it in the future (seems like they already did it) in order to force us to pay for storage using firebase. Ok, fine, but how do I migrate it if I can't access the folder via googleapi? If I reset my app now and my users lose all their data I'll lose the few users I have...

Dpedrinha
  • 3,741
  • 3
  • 38
  • 57

1 Answers1

5

The following works for me, (using the http package for get and post)

Auth Token

You can retrieve the auth token from the accoutn returned by signIn.

Future<String> _getAuthToken() async {
  final account = await sign_in_options.signIn();
  if (account == null) {
    return null;
  }
  final authentication = await account.authentication;
  return authentication.accessToken;
}

Search

To search files in the AppData directory you need to add the spaces queryParameters and set it to appDataFolder. The documentation is kind of misleading on that part.

final Map<String, String> queryParameters = {
  'spaces': 'appDataFolder',
  // more query parameters
};
final headers = { 'Authorization': 'Bearer $authToken' };
final uri = Uri.https('www.googleapis.com', '/drive/v3/files', queryParameters);
final response = await get(uri, headers: headers);

Upload

To upload a file you need to set the parents to appDataFolder property of the body for the initial upload request. To download the file you only need the fileId.

final headers = { 'Authorization': 'Bearer $authToken' };
final initialQueryParameters = { 'uploadType': 'resumable' };
final Map<String, dynamic> metaData = { 
  'name': fileName,
  'parents': ['appDataFolder ']
};
final initiateUri = Uri.https('www.googleapis.com', '/upload/drive/v3/files', initialQueryParameters);
final initiateResponse = await post(initiateUri, headers: headers, body: json.encode(metaData));
final location = initiateResponse.headers['location'];

Download

To download the file you only need to know the fileId, if you don't know it you need to use the search API to retrieve it (see above).

final headers = { 'Authorization': 'Bearer $authToken' };
final url = 'https://www.googleapis.com/drive/v3/files/$fileId?alt=media';
final response = await get(url, headers: headers);
surrz
  • 295
  • 2
  • 11
  • 1
    Thanks I'll try that out. But how do you get the $authToken? – Dpedrinha Sep 26 '19 at 13:48
  • 1
    Also how did you implement 'get' and 'post' methods? – Dpedrinha Sep 26 '19 at 15:12
  • I'm getting reasonPhrase: Forbidden with your search code. Do I need other query parameters? Or should this work as it is? – Dpedrinha Sep 26 '19 at 17:27
  • Hmm it seems its trying to get permission for the wrong app. It's trying to get my flutter app name instead of my Android app name. Is it possible to set the app name on the requests? Because I don't know what else to change. pubspeck.yaml won't accept my app name since it contains spaces. Android files seem to be set up correctly. – Dpedrinha Sep 26 '19 at 17:58
  • 1
    Yep, the problem was that it was using flutter app name instead of Android's to get the app folder. Fixed. – Dpedrinha Sep 27 '19 at 02:45
  • This example it the first part of uploading a file. Once you've got the location you'll need to do something like this: final uploadResponse = await put(location, headers: headers, body: '{text: 123}'); – Andrew Oct 28 '19 at 16:38