RonRadtke / react-native-blob-util

A project committed to making file access and data transfer easier, efficient for React Native developers.
MIT License
749 stars 128 forks source link

support downloading file in background on iOS #320

Open truongnguyen3 opened 9 months ago

truongnguyen3 commented 9 months ago

Motivation the URLSession has one function that allows us to download files in background execution (correct me if I am wrong). Here's the document I found in Xcode: image

Details When downloading files, apps should use an NSURLSession object to start the downloads so that the system can take control of the download process in case the app is suspended or terminated. When you configure an NSURLSession object for background transfers, the system manages those transfers in a separate process and reports status back to your app in the usual way. If your app is terminated while transfers are ongoing, the system continues the transfers in the background and launches your app (as appropriate) when the transfers finish or when one or more tasks need your app’s attention.

To support background transfers, you must configure your NSURLSession object appropriately. To configure the session, you must first create a NSURLSessionConfiguration object and set several properties to appropriate values. You then pass that configuration object to the appropriate initialization method of NSURLSession when creating your session.

The process for creating a configuration object that supports background downloads is as follows:

Create the configuration object using the backgroundSessionConfigurationWithIdentifier: method of NSURLSessionConfiguration. Set the value of the configuration object’s sessionSendsLaunchEvents property to YES. if your app starts transfers while it is in the foreground, it is recommend that you also set the discretionary property of the configuration object to YES. Configure any other properties of the configuration object as appropriate. Use the configuration object to create your NSURLSession object. Once configured, your NSURLSession object seamlessly hands off upload and download tasks to the system at appropriate times. If tasks finish while your app is still running (either in the foreground or the background), the session object notifies its delegate in the usual way. If tasks have not yet finished and the system terminates your app, the system automatically continues managing the tasks in the background. If the user terminates your app, the system cancels any pending tasks.

When all of the tasks associated with a background session are complete, the system relaunches a terminated app (assuming that the sessionSendsLaunchEvents property was set to YES and that the user did not force quit the app) and calls the app delegate’s application:handleEventsForBackgroundURLSession:completionHandler: method. (The system may also relaunch the app to handle authentication challenges or other task-related events that require your app’s attention.) In your implementation of that delegate method, use the provided identifier to create a new NSURLSessionConfiguration and NSURLSession object with the same configuration as before. The system reconnects your new session object to the previous tasks and reports their status to the session object’s delegate.

refs:

crackhack8266 commented 9 months ago

any solutions ?

truongnguyen3 commented 9 months ago

@crackhack8266 we need someone to work on it. I did create another issue in https://github.com/edeckers/react-native-blob-courier/issues/251 the package react-native-blob-courier focuses on download and upload tasks, So it just needs a little change to support download tasks on background execution in iOS

RonRadtke commented 9 months ago

Thank you for the input. It sure would be nice to have and probably change the whole ios implementation. But currently I don't have the amount of free time to implement this

truongnguyen3 commented 9 months ago

Thanks for your reply. I am currently learning iOS native development, maybe I will contribute to your repo later if I can.

RonRadtke commented 5 months ago

Thanks for your reply. I am currently learning iOS native development, maybe I will contribute to your repo later if I can.

Would be great. How is it going? Any way I can help you getting going with iOS native development?

utkuimd commented 4 months ago

Hey guys, i have a solution and created PR for this. @RonRadtke https://github.com/RonRadtke/react-native-blob-util/pull/368

RonRadtke commented 3 months ago

Hey guys, i have a solution and created PR for this. @RonRadtke #368

You're awesome thank you! Or is merged and will be part of the next release

maksymhcode-care commented 2 months ago

Hey guys, i have a solution and created PR for this. @RonRadtke #368

You're awesome thank you! Or is merged and will be part of the next release

Any plans to release it?

maksymhcode-care commented 2 months ago

@RonRadtke @utkuimd It gives me 'The network connection was lost' error if i swith to background for a few seconds, any thoughts on this?

maksymhcode-care commented 1 month ago

Hey guys, i have a solution and created PR for this. @RonRadtke #368

You're awesome thank you! Or is merged and will be part of the next release

Have i missed a part in the documentation that is supposed to describe how to use background download? For example, i had no idead IOSBackgroundTask needs to used, maybe i missed something else

RonRadtke commented 1 month ago

Setting IOSBackgroundTask=true should be all you have to do. Does that happen immediately or after a certain time? Does it always happen? Maybe you have a short snipped I can use to try to reproduce it

maksymhcode-care commented 1 month ago

Setting IOSBackgroundTask=true should be all you have to do. Does that happen immediately or after a certain time? Does it always happen? Maybe you have a short snipped I can use to try to reproduce it

Now i get this error "Lost connection to background transfer service"
Usually happens immediately, in same rare moments it can leave up to 30 seconds
const url = '***'
  const title ='Video.mov';
  const dirs = ReactNativeBlobUtil.fs.dirs;
  const filePath = `${dirs.DownloadDir}/${title}`;
  const res = ReactNativeBlobUtil.config({
    addAndroidDownloads: {
      useDownloadManager: true,
      path: filePath,
      notification: false,
      title: title,
      description: "Downloading.",
    },
    timeout: 12000,
    appendExt: "mov",
    fileCache: true,
    path: (constants.isIOS ? dirs.DocumentDir : dirs.DownloadDir) + `/${title}`,
    IOSBackgroundTask: true,
  })
    .fetch("GET", url)
 return res;

I also tried using code from this thread, is that necessary? https://github.com/joltup/rn-fetch-blob/issues/426

RonRadtke commented 1 month ago

I removed the url. S3 URLs can get expensive if miss-used. And some credential part was in it too

Thank you for the snipped

maksymhcode-care commented 1 month ago

I removed the url. S3 URLs can get expensive if miss-used. And some credential part was in it too

Thank you for the snipped

Thanks

RonRadtke commented 1 month ago

@maksymhcode-care can you see any details in xcode? Like the exact error message from the system? Often the error code describe a bit more in detail what is going on compared to the textual description

maksymhcode-care commented 1 month ago

@maksymhcode-care can you see any details in xcode? Like the exact error message from the system? Often the error code describe a bit more in detail what is going on compared to the textual description

No, i only get "Lost connection to background transfer service" from catch handler. And it only happens on ios on a real device, no issue on ios simulator, android emulator, android device

RonRadtke commented 1 month ago

Same iOS version for the simulator and the real device?

Kinda sounds like it actually could be due to an unstable connection. Did you try it with an other network connection once? Like at home / work or wifi / no wifi?

maksymhcode-care commented 1 month ago

Same iOS version for the simulator and the real device?

Kinda sounds like it actually could be due to an unstable connection. Did you try it with an other network connection once? Like at home / work or wifi / no wifi?

17.5 - simulator, 17.6 - phone. Using my home wifi, no issues on foreground, only when i switch to a background

ShivamBarot2602 commented 1 month ago

@RonRadtke Can you please provide us a direct implementation of uploading tasks when the app goes into background in IOS. It is a much required thing and no npm package is giving a support for this. Currently i am using rn-fetch-blob library to handle upload tasks but it is not behaving as expected. Would love to contribute to your repository if you can help and guide us in implementing and integrating it in your package.

Due to lack of this functionality i am stuck on a high priority bug at my organization.

IMG_70EC4AF31CD0-1

maksymhcode-care commented 1 month ago

@RonRadtke Can you please provide us a direct implementation of uploading tasks when the app goes into background in IOS. It is a much required thing and no npm package is giving a support for this. Currently i am using rn-fetch-blob library to handle upload tasks but it is not behaving as expected. Would love to contribute to your repository if you can help and guide us in implementing and integrating it in your package.

Due to lack of this functionality i am stuck on a high priority bug at my organization.

IMG_70EC4AF31CD0-1

Hope we can resolve it

utkuimd commented 1 month ago

Setting IOSBackgroundTask=true should be all you have to do. Does that happen immediately or after a certain time? Does it always happen? Maybe you have a short snipped I can use to try to reproduce it

Now i get this error "Lost connection to background transfer service"
Usually happens immediately, in same rare moments it can leave up to 30 seconds
const url = '***'
  const title ='Video.mov';
  const dirs = ReactNativeBlobUtil.fs.dirs;
  const filePath = `${dirs.DownloadDir}/${title}`;
  const res = ReactNativeBlobUtil.config({
    addAndroidDownloads: {
      useDownloadManager: true,
      path: filePath,
      notification: false,
      title: title,
      description: "Downloading.",
    },
    timeout: 12000,
    appendExt: "mov",
    fileCache: true,
    path: (constants.isIOS ? dirs.DocumentDir : dirs.DownloadDir) + `/${title}`,
    IOSBackgroundTask: true,
  })
    .fetch("GET", url)
 return res;

I also tried using code from this thread, is that necessary? joltup#426

I have changed your code a little bit and i tried download a sample file on background for real iOS(16.6) device.

const url = fileUri_70MB_Zip;
const title = 'Deneme.zip';
const dirs = ReactNativeBlobUtil.fs.dirs;
const filePath = `${dirs.DownloadDir}/${title}`;

ReactNativeBlobUtil.config({
  addAndroidDownloads: {
    useDownloadManager: true,
    path: filePath,
    notification: false,
    title: title,
    description: 'Downloading...',
  },
  timeout: 12000,
  appendExt: 'zip',
  fileCache: true,
  path:
    (Platform.OS === 'ios' ? dirs.DocumentDir : dirs.DownloadDir) +
    `/${title}`,
  IOSBackgroundTask: true,
})
  .fetch('GET', url)
  .progress((received, total) => {
    const percentage = Math.floor((Number(received) / Number(total)) * 100);
    setProgress(percentage);
    console.log('Test download progress:', percentage);
  })
  .then(res => {
    const isDownloaded = res.path().length > 0;
    setProgress(undefined);
    console.log('is downloaded:', isDownloaded);
  })
  .catch(err => console.error(err));

The download completed on background without any problems.

Can you check your local node_modules/react-native-blob-util/ios/ReactNativeBlobUtilRequest.mm file have didFinishDownloadingToURL and didWriteData instance methods?

utkuimd commented 1 month ago

@RonRadtke Can you please provide us a direct implementation of uploading tasks when the app goes into background in IOS. It is a much required thing and no npm package is giving a support for this. Currently i am using rn-fetch-blob library to handle upload tasks but it is not behaving as expected. Would love to contribute to your repository if you can help and guide us in implementing and integrating it in your package.

Due to lack of this functionality i am stuck on a high priority bug at my organization.

IMG_70EC4AF31CD0-1

Hi, I only developed for downloading tasks on background, not for uploading tasks and i don't think developed that in the near future.

We can change IOSBackgroundTask property name like IOSDownloadBackgroundTask for prevent confusion. What do you say about that? @RonRadtke

maksymhcode-care commented 1 month ago

Setting IOSBackgroundTask=true should be all you have to do. Does that happen immediately or after a certain time? Does it always happen? Maybe you have a short snipped I can use to try to reproduce it

Now i get this error "Lost connection to background transfer service"
Usually happens immediately, in same rare moments it can leave up to 30 seconds
const url = '***'
  const title ='Video.mov';
  const dirs = ReactNativeBlobUtil.fs.dirs;
  const filePath = `${dirs.DownloadDir}/${title}`;
  const res = ReactNativeBlobUtil.config({
    addAndroidDownloads: {
      useDownloadManager: true,
      path: filePath,
      notification: false,
      title: title,
      description: "Downloading.",
    },
    timeout: 12000,
    appendExt: "mov",
    fileCache: true,
    path: (constants.isIOS ? dirs.DocumentDir : dirs.DownloadDir) + `/${title}`,
    IOSBackgroundTask: true,
  })
    .fetch("GET", url)
 return res;

I also tried using code from this thread, is that necessary? joltup#426

I have changed your code a little bit and i tried download a sample file on background for real iOS(16.6) device.

const url = fileUri_70MB_Zip;
const title = 'Deneme.zip';
const dirs = ReactNativeBlobUtil.fs.dirs;
const filePath = `${dirs.DownloadDir}/${title}`;

ReactNativeBlobUtil.config({
  addAndroidDownloads: {
    useDownloadManager: true,
    path: filePath,
    notification: false,
    title: title,
    description: 'Downloading...',
  },
  timeout: 12000,
  appendExt: 'zip',
  fileCache: true,
  path:
    (Platform.OS === 'ios' ? dirs.DocumentDir : dirs.DownloadDir) +
    `/${title}`,
  IOSBackgroundTask: true,
})
  .fetch('GET', url)
  .progress((received, total) => {
    const percentage = Math.floor((Number(received) / Number(total)) * 100);
    setProgress(percentage);
    console.log('Test download progress:', percentage);
  })
  .then(res => {
    const isDownloaded = res.path().length > 0;
    setProgress(undefined);
    console.log('is downloaded:', isDownloaded);
  })
  .catch(err => console.error(err));

The download completed on background without any problems.

Can you check your local node_modules/react-native-blob-util/ios/ReactNativeBlobUtilRequest.mm file have didFinishDownloadingToURL and didWriteData instance methods?

I only have it here image

Can you also try downloading a big file? ~2 gigabytes, i had no issue with small files, usually downloading can work for up to 30 seconds, and then i have an error