Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The dark side of Background tasks in React Native - React Alicante 2018

ferrannp
September 15, 2018

The dark side of Background tasks in React Native - React Alicante 2018

In this talk we are going to explore how to manage background tasks within your React Native application. Background tasks are essentially tasks that run when the app is not in the foreground (visible).

ferrannp

September 15, 2018
Tweet

Other Decks in Programming

Transcript

  1. Audio, AirPlay and Picture in Picture Location updates Newsstand downloads

    External accessory communication Use Bluetooth LE accessories Act as Bluetooth LE accessory Background fetch Remote notifications
  2. JS initPlayer = async () => { try { await

    TrackPlayer.setupPlayer(); } catch (e) { // Error } };
  3. iOS @objc(setupPlayer:resolver:rejecter:) func setupPlayer( config: [String: Any], resolve: RCTPromiseResolveBlock, reject:

    RCTPromiseRejectBlock) { do { try AVAudioSession.sharedInstance() .setCategory(AVAudioSessionCategoryPlayback) try AVAudioSession.sharedInstance() .setActive(true) } catch { reject(error) } resolve(NSNull()) }
  4. Android @ReactMethod public void setupPlayer(ReadableMap data, final Promise promise) {

    final Bundle options = Arguments.toBundle(data); waitForConnection(new Runnable() { @Override public void run() { binder.setupPlayer(options, promise); } }); }
  5. JS playNewTrack = async () => { const { track

    } = this.props; await TrackPlayer.add(track); await TrackPlayer.play(); };
  6. iOS

  7. Android private void waitForConnection(Runnable r) { ... Intent intent =

    new Intent(context, PlayerService.class); context.startService(intent); intent.setAction(PlayerService.ACTION_CONNECT); ... }
  8. Android public void destroyPlayer() { playback.destroy(); if(!Utils.isStopped(playback.getState())) { onStop(); }

    playback = null; if(serviceStarted) { service.stopSelf(); serviceStarted = false; } }
  9. Headless JS protected void startTask( final HeadlessJsTaskConfig taskConfig ) {

    ... reactInstanceManager .createReactContextInBackground(); ... invokeStartTask(reactContext, taskConfig); ... }
  10. Setup Headless JS - Native public class SyncShowsService extends HeadlessJsTaskService

    { @Override protected HeadlessJsTaskConfig getTaskConfig(Intent intent) { return new HeadlessJsTaskConfig( "SyncShowsTask", null, // We could pass arguments 120000, // Timeout in ms false // Task is allowed in foreground ); } } <service android:name=“com.me.mypackage.SyncShowsService” /> …also on your AndroidManifest.xml
  11. Setup Headless JS - JS module.exports = async (taskData) =>

    { // Sync code }; AppRegistry .registerHeadlessTask(‘SyncShowsTask', () => require(‘./SyncShowsTask’));
  12. When to start it? “ Now, whenever you start your

    service, e.g. as a periodic task or in response to some system event / broadcast, JS will spin up, run your task, then spin down. “
  13. JS import SyncAdapter from 'react-native-sync-adapter'; class MyRoot extends Component {

    componentDidMount() { SyncAdapter.init({ syncInterval, syncFlexTime, }); } } AppRegistry .registerHeadlessTask('TASK_SYNC_ADAPTER', () => SyncShowsTask);
  14. Android @ReactMethod public void init(int syncInterval, int syncFlexTime) { //

    All Java code described in Android docs } @Override public void onPerformSync(...) { Intent service = new Intent( getContext(), HeadlessService.class ); getContext().startService(service); }
  15. iOS Background Fetch Mode Network availability Device is awake Data

    & time previous attempt 30 seconds every 15 minutes
  16. iOS

  17. JS import BackgroundFetch from 'react-native-background-fetch'; BackgroundFetch.configure( { minimumFetchInterval: 240 },

    () => { setTimeout(() => { console.log(‘[JS] Finish'); BackgroundFetch.finish(); }, 30000); // Sync code }, error => { console.log('[JS] Error', error); } );
  18. iOS - (void) performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult)) handler applicationState:(UIApplicationState)state { NSLog(@"[%@ performFetchWithCompletionHandler]",

    TAG); if (!hasReceivedEvent) { hasReceivedEvent = YES; launchedInBackground = (state == UIApplicationStateBackground); } ... for (NSString* componentName in listeners) { void (^callback)() = [listeners objectForKey:componentName]; callback(); } ... }
  19. Android - Be aware New background limitations: https:// developer.android.com/about/versions/ oreo/background

    (API 26) JobScheduler (API 21), SyncAdapter startForegroundService (API 26)
  20. React Native The bridge Activity Service (Headless) Waking up mechanisms

    (receivers, SyncAdapter, etc) App instance Background modes (+ waking up mechanisms) JS task
 (same Android & iOS)