Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload file to google drive with googleapis in Background (Flutter)

I can upload files to google drive with googleapis in the foreground but I need to upload files in the background in my flutter app. I tried to upload with workmanager but it doesn't work. Here is some necessary part of the code for this post of my app:

...
@override
  void initState() {
    WidgetsFlutterBinding.ensureInitialized();
    Workmanager.initialize(callbackDispatcher, isInDebugMode: true);
    Workmanager.registerPeriodicTask("1", "simplePeriodicTask",
        existingWorkPolicy: ExistingWorkPolicy.replace,
        frequency: Duration(hours: 1),
        initialDelay:
            Duration(seconds: 5),
        constraints: Constraints(
          networkType: NetworkType.connected,
        ));
    super.initState();
    login()
  }
...

...

This is for background task:

...
void callbackDispatcher() {
  Workmanager.executeTask((task, inputData) {
    login();
    _HomeState().uploadFileL();
    print('Background Services are Working!');
    return Future.value(true);
  });
}
...

...

This is for upload file:

...
Future<void> uploadFileL() async {
    final filename = 'Location.db';
    final gFile = ga.File();
    gFile.name = filename;
    final dir = await getExternalStorageDirectory();
    final localFile = File('${dir.path}/$filename');
    final createdFile = await api.files.create(gFile,
        uploadMedia: ga.Media(localFile.openRead(), localFile.lengthSync()));
    print('New file created ${createdFile.id}');
    setState(() {});
  }
...

For login:

class GoogleHttpClient extends IOClient {
  Map<String, String> _headers;

  GoogleHttpClient(this._headers) : super();

  @override
  Future<IOStreamedResponse> send(BaseRequest request) =>
      super.send(request..headers.addAll(_headers));

  @override
  Future<Response> head(Object url, {Map<String, String> headers}) =>
      super.head(url, headers: headers..addAll(_headers));
}

...

...
Future<void> login() async {
    try {
      account = await _googleSignIn.signIn();
      final client =
          GoogleHttpClient(await _googleSignIn.currentUser.authHeaders);
      api = ga.DriveApi(client);
    } catch (error) {
      print('DriveScreen.login.ERROR... $error');
      _scaffold.currentState.showSnackBar(SnackBar(
        backgroundColor: Colors.red.shade700,
        content: Text(
          'Error : $error',
          style: TextStyle(color: Colors.white),
        ),
      ));
    }
    setState(() {});
  }
...

I think the possible cause of this problem is, It can not find the auth client in the background to upload files. What's your thought? and if I am right what will be the solution?

like image 562
Santo Shakil Avatar asked Jul 07 '20 12:07

Santo Shakil


People also ask

Can you upload to Google Drive in the background?

Videos will be uploaded to Google Drive automatically in the background.

Does Google Drive throttle uploads?

Drive upload limitsIndividual users can only upload 750 GB each day between My Drive and all shared drives. Users who reach the 750-GB limit or upload a file larger than 750 GB cannot upload additional files that day. Uploads that are in progress will complete.


1 Answers

For those who still need an answer to this question:

We have to use the method: signInSilently() that attempts to login using previously authenticated account without any user interaction. Suitable to use in background services.

Future<void> upload(context) async {
    GoogleSignInAccount? account = await googleSignIn.signInSilently();
    if (account == null) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
        content: Text("Not logged in"),
      ));
      return;
    }
    final authHeaders = await account.authHeaders;
    final authenticateClient = GoogleAuthClient(authHeaders);
    final driveApi = drive.DriveApi(authenticateClient);

    final Stream<List<int>> mediaStream =
        Future.value([104, 105]).asStream().asBroadcastStream();
    var media = drive.Media(mediaStream, 5);
    var driveFile = drive.File();
    driveFile.name = "hello_world.txt";
    final result = await driveApi.files.create(driveFile, uploadMedia: media);
    print("Upload result: ${result.name}");
}
like image 95
rehman_00001 Avatar answered Nov 15 '22 08:11

rehman_00001