fluttercommunity/flutter_uploader

Uploading stops when the device is locked.

w3ggy opened this issue · 3 comments

w3ggy commented

The case:
I want to make my app uploading 500-1000 images in the background even when the device is locked. Everything works fine when the app is in the foreground.

The issue:
When I lock the device, I don't receive any events neither in Flutter nor in native. Now it is impossible to debug the Flutter iOS app when the device is locked. Thus, I am trying to debug the native one.

The code for scheduling uploading on the Flutter side:

await Future.wait(notUploadedPhotos.map((photo) async {
      final taskId = await uploader.enqueue(
        MultipartFormDataUpload(
          url: '${rowService.apiClient.environment.baseUrl}photos/',
          files: [FileItem(path: '$basePath${photo.path!}', field: 'file')],
          method: UploadMethod.POST,
          headers: {'Authorization': 'Bearer $token'},
          allowCellular: allowCellular,
        ),
      );

      await galleryService.updatePhoto(photo.copyWith(taskId: taskId));
    }));

The background:

  • I tried to set the breakpoints in Xcode and don't receive anything after a while. I don't receive any errors at all.
image
  • Do we need to disable Data protection for the app or set a specific level? I saw some problems with those settings on stackoverflow.com but not sure that it is a key
  • Sometimes the app crashes when I try to create a task with 1000 files or 1000 tasks. Looks like related to #209
  • I saw the same question previously without response: #165 about background uploading
  • Did I miss something? There is nothing special for ios in the readme. Maybe I don't know what I need to set up to make it work?
w3ggy commented

After logs investigation I see:

image

but there is no successful message:

image

Looks strange like uploadTasks is not empty but urlSessionDidFinishEvents has been called:

image

I see URLSessionDidCompleteWithError after URLSessionDidFinishEvents


2022-02-15 23:13:17.568849+0400 Runner[20204:1011071] URLSessionDidFinishEvents:
2022-02-15 23:13:17.569594+0400 Runner[20204:1010718] URLSessionDidCompleteWithError: chillisource.flutter_uploader.upload.background.25F06BE6-E4AD-4E30-AF59-BB03444803EE with response: <NSHTTPURLResponse: 0x282a91020> { URL: https://qa.app.ai/api/v1/photos/ } { Status Code: 201, Headers {
    "Alt-Svc" =     (
        clear
    );
    "Content-Length" =     (
        219
    );
    "Content-Type" =     (
        "application/json"
    );
    Date =     (
        "Tue, 15 Feb 2022 19:13:15 GMT"
    );
    Server =     (
        nginx
    );
    Vary =     (
        Accept
    );
    Via =     (
        "1.1 google"
    );
    allow =     (
        "POST, OPTIONS"
    );
    "referrer-policy" =     (
        "same-origin",
        "same-origin"
    );
    "x-content-type-options" =     (
        nosniff
    );
    "x-frame-options" =     (
        DENY
    );
} } and status: 201
2022-02-15 23:13:17.569776+0400 Runner[20204:1010718] URLSessionDidCompleteWithError: upload completed

but according to pattern of the message it is the following line which is ok:

image

My thoughts about this problem:

When I lock the device, the system calls the urlSessionDidFinishEvents after some time seconds but I still have uploadTasks. Is it the desired behavior by Apple? How to make uploading all tasks in queue?

w3ggy commented

Intermediate results of my investigation:

I noticed that urlSessionDidFinishEvents is called but uploadTasks is not empty. It is ok according to the doc: https://developer.apple.com/documentation/foundation/nsurlsession/1411578-gettaskswithcompletionhandler

I received the following logs:

public func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        NSLog("URLSessionDidFinishEvents:")

        session.getTasksWithCompletionHandler { (_, uploadTasks, _) in
            NSLog("URLSessionDidFinishEvents:2")
            self.semaphore.wait()
            defer {
                self.semaphore.signal()
            }
            
            if uploadTasks.isEmpty {
                NSLog("all upload tasks have been completed")

                self.backgroundTransferCompletionHander?()
                self.backgroundTransferCompletionHander = nil
            } else {
                NSLog("tasks count: \(uploadTasks.count)")
                
                for task in uploadTasks {
                    NSLog("tasks state: \(task.state.statusText())")
                }
            }
        }
    }
2022-02-17 18:06:19.567188+0400 Runner[31920:1714833] tasks count: 2
2022-02-17 18:06:19.567454+0400 Runner[31920:1714833] tasks state: completed
2022-02-17 18:06:19.568021+0400 Runner[31920:1714833] tasks state: completed

uploadTasks are completed but not empty. Any ideas why?

@w3ggy did you find any solution for this issue ?