8

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?

Santo Shakil
  • 981
  • 2
  • 13
  • 27

1 Answers1

1

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}");
}
rehman_00001
  • 1,299
  • 1
  • 15
  • 28