kesha-antonov / react-native-background-downloader

About A library for React-Native to help you download large files on iOS and Android both in the foreground and most importantly in the background.
https://www.npmjs.com/package/@kesha-antonov/react-native-background-downloader
Other
25 stars 3 forks source link

feat: expo config plugin for iOS native code #9

Open castdrian opened 1 month ago

castdrian commented 1 month ago

it’d be cool if this lib would provide an expo config plugin to perform the native code change in the AppDelegate, since managed projects regenerate the native code when they build

kesha-antonov commented 1 month ago

Hi Nice idea! If you can please submit PR I can also check how to do it on the weekend

castdrian commented 1 month ago

Yeah I'll see to get to it if I have time, it's fairly easy to do thankfully, expo exposes direct apis to inject code into the AppDelegate, this is a nice explanation: https://www.sitepen.com/blog/doing-more-with-expo-using-custom-native-code

kesha-antonov commented 1 month ago

Thanks for the hint!

mtshv commented 1 month ago

Yo guys, Sharing my expo config plugin for AppDelegate modification. Works fine so far:

const { withAppDelegate } = require('@expo/config-plugins');

function withRNBackgroundDownloader(expoConfig) {
  return withAppDelegate(expoConfig, async appDelegateConfig => {
    const { modResults: appDelegate } = appDelegateConfig;
    const appDelegateLines = appDelegate.contents.split('\n');

    // Define the code to be added to AppDelegate.mm
    const backgroundDownloaderImport =
      '#import <RNBackgroundDownloader.h> // Required by react-native-background-downloader. Generated by expoPlugins/withRNBackgroundDownloader.js';
    const backgroundDownloaderDelegate = `\n// Delegate method required by react-native-background-downloader. Generated by expoPlugins/withRNBackgroundDownloader.js
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler
{
  [RNBackgroundDownloader setCompletionHandlerWithIdentifier:identifier completionHandler:completionHandler];
}`;

    // Find the index of the AppDelegate import statement
    const importIndex = appDelegateLines.findIndex(line =>
      /^#import "AppDelegate.h"/.test(line),
    );

    // Find the index of the last line before the @end statement
    const endStatementIndex = appDelegateLines.findIndex(line =>
      /@end/.test(line),
    );

    // Insert the import statement if it's not already present
    if (!appDelegate.contents.includes(backgroundDownloaderImport)) {
      appDelegateLines.splice(importIndex + 1, 0, backgroundDownloaderImport);
    }

    // Insert the delegate method above the @end statement
    if (!appDelegate.contents.includes(backgroundDownloaderDelegate)) {
      appDelegateLines.splice(
        endStatementIndex,
        0,
        backgroundDownloaderDelegate,
      );
    }

    // Update the contents of the AppDelegate file
    appDelegate.contents = appDelegateLines.join('\n');

    return appDelegateConfig;
  });
}

module.exports = withRNBackgroundDownloader;

I'd open a PR to add it, but I do not know the appropriate place to put this code 🤷

castdrian commented 1 month ago

yup that config plugin works like a charm, well done