React Native and Native Modules: The Android SyncAdapter

  • React Native and Native Modules: The Android SyncAdapterReact Native and Android have been friends for a whileI came into the need of using a SyncAdapter for an Android app I want to fully convert into React Native.
  • For this native module that I named as react-native-sync-background, we are gonna combine the Android SyncAdapter with the HeadlessJS.
  • In there, we want to start our HeadlessJS so we can write all the actual sync code in JavaScript (like fetching from an API):Our HeadlessService.class is almost the same as the one explained on the docs but with some extra checks:There are several things worth mentioning here:new HeadlessJsTaskConfig( TASK_ID, null, 300000);We hardcoded our TASK_ID to be TASK_SYNC_BACKGROUND so you will need to register a task with this exact same name and that is the task our SyncAdapter will runWe pass null as parameter so the actual JS task will receive null as extra (since we do not need any param)Default timeout is set to 5 minutes which should be enough for any task of this kind.
  • If we actually return just null, it will start a non-sticky Service that will not be stopped (which is bad for memory/battery) so we make sure that we handle this edge case.Creating the moduleLet’s go ahead and create a native module, named SyncBackground that will be responsible for interacting with our SyncAdapter:Basically we do two things here:Override getName so from now on, our Native Module will be called SyncBackgroundExpose (using @ReactMethod), in this case, just the method init that will set up all the sync hassle for usNow, loading that module is just a matter of adding a new instance of it to the native modules list, as shown below:So the apps that want to actually use this module will be able to add new SyncBackgroundPackage() just as we do in the example app.More on the native side, we want our module to act as an Android library so we can use it in other projects, to do so, take a look at the build.gradle file.
  • To your question: Yes, I AM A WIZARD.By the way, notice at the second screenshot, you can select the option Sync Now which will trigger onPerformSync which will trigger your HeadlessJS task so you can try it out without waiting at all.Exposing a typed APII find it nice not to expose the Native Module as it is, but wrap it into your own API where you can actually use some typing (Hello Flow!)

I came into the need of using a SyncAdapter for an Android app I want to fully convert into React Native. In this app, I already have the native piece of code working and I could not find a library…

@ferrannp: I just published “React Native and Native Modules: The Android SyncAdapter” Thanks to @grabbou @callstackio

React Native and Native Modules: The Android SyncAdapter

I came into the need of using a SyncAdapter for an Android app I want to fully convert into React Native. In this app, I already have the native piece of code working and I could not find a library out there that actually exposes such functionality. This is how I ended up writing it by myself.

What is the SyncAdapter ?

Basically it is a framework that Android provides to synchronize the data between an Android device and web servers. You could design your own, but they always recommended to use their solution since it provides you with several nice features that you cannot implement by yourself. Basically:

You can read more advantages here.

What is the HeadlessJS ?

It is just another Native Module that wraps an Android Service which starts the JavaScript engine where you can run background tasks written in JavaScript. Headless JS is part of React Native since version 0.36.0.

, we are gonna combine the Android SyncAdapter with the HeadlessJS. Let’s start!

I will not go into details in this part but it is a must to use Android Studio. It will provide you with auto-imports and tones of other features. For writing native code, I have basically followed Creating a Sync Adapter training. If you want to read through the code you can do it here. For this section, I am actually going to focus on parts of the code that would actually be new for an Android developer (including React Native code interaction).

(see this file). In there, we want to start our HeadlessJS so we can write all the actual sync code in JavaScript (like fetching from an API):

is almost the same as the one explained on the docs but with some extra checks:

There are several things worth mentioning here:

new HeadlessJsTaskConfig(

TASK_ID,

null,

check? From the docs:

By default, your app will crash if you try to run a task while the app is in the foreground. This is to prevent developers from shooting themselves in the foot by doing a lot of work in a task and slowing the UI. There is a way around this.

Indeed there is a way around this which is taking a look at the source code and passing a specific parameter. But, I prefer to stick into only launching the service when the app is in the background. My workaround would be:

, it will start a non-sticky Service that will not be stopped (which is bad for memory/battery) so we make sure that we handle this edge case.

Creating the module

Basically we do two things here:

Now, loading that module is just a matter of adding a new instance of it to the native modules list, as shown below:

just as we do in the example app.

More on the native side, we want our module to act as an Android library so we can use it in other projects, to do so, take a look at the build.gradle file. The only required thing to convert our module into an Android library (so Android won’t generate an apk for it) is to add the following line:

apply plugin: ‘com.android.library’

To learn more check Create an Android library.

And voilà! Our library is ready to be consumed.

in this case) plus our app launcher icon. If you check the Android library considerations:

Resource merge conflicts: The build tools merge resources from a library module with those of a dependent app module. If a given resource ID is defined in both modules, the resource from the app is used.

and define the same resource name in your app, the one from your app will take precedence. We can take advantage of this since our SyncAdapter needs unique values for each app, so in the app that we will be using this library, we should override these values:

which is also a default pattern.

you will see how the strings and the launcher icon are correctly being overridden:

As you can see, the values that are used are from our app and not from the library. To your question: Yes, I AM A WIZARD.

which will trigger your HeadlessJS task so you can try it out without waiting at all.

I find it nice not to expose the Native Module as it is, but wrap it into your own API where you can actually use some typing (Hello Flow!).

Indeed, I could expose this library as:

import { NativeModules } from ‘react-native’;

export default NativeModules.SyncBackground;

But as I said, I would like to provide a more JS-like API and provide Flow types so we make sure we use the library correctly. Here is this tiny API:

I use an Object as parameter so it is easy to extend it in the future without breaking changes. Flow will make sure you call the function with correct parameters plus I do some error checking. Therefore, the internal implementation is totally transparent to the user and they do not need to know/care how do I use/call functions in the native (Java) code.

Our native module is ready to use. You can actually follow the setup instructions in the repository: https://github.com/ferrannp/react-native-sync-background.

Thanks to React Native modular approach, when one solves a problem on Android (that we do not really want to solve ourselves), then you do not need to do it by yourself never again. Which is nice, isn’t it?

Let me know what you think in the comments below and if you would like me to continue writing about Native Modules even if they are simple examples.

Happy coding!

React Native and Native Modules: The Android SyncAdapter