Adding a third-party SDK like Button requires the creation of a Native Module to expose its functionalities to JavaScript.

Below, we'll show you how we approached this problem while integrating the Button SDK into our delivery.com Android app.

For a complete sample app, check out this Github repo.

From JavaScript to Java and vice versa

After adding the Button SDK to your Android app (here's a helpful guide), you'll have to add three more files: two Java and one JavaScript.

The first is the Button Native Module Package, which is the standard way of registering a Native Module into a React Native Android application. This is essentially a template for any Native Module you want to create.

Button.java

public class ButtonPackage implements ReactPackage {<br><br> private Button mModuleInstance;<br><br> @Override<br> public List&lt;NativeModule&gt; createNativeModules(ReactApplicationContext reactContext) {<br> List&lt;NativeModule&gt; modules = new ArrayList&lt;&gt;();<br> mModuleInstance = new Button(reactContext);<br><br> modules.add(mModuleInstance);<br> return modules;<br> }<br><br> @Override<br> public List&lt;Class&lt;? extends JavaScriptModule&gt;&gt; createJSModules(){<br> return Collections.emptyList();<br> }<br><br> @Override<br> public List&lt;ViewManager&gt; createViewManagers(ReactApplicationContext reactContext) {<br> return Collections.emptyList();<br> }<br><br>}

The second Java class file will be invoked when you execute any function or method from the JavaScript side of your Button Native Module.

Button.java

public class Button extends ReactContextBaseJavaModule {<br><br> @Override<br> public String getName() {<br> return "Button";<br> }<br><br> public Button(ReactApplicationContext reactContext) {<br> super(reactContext);<br> }<br><br> ...<br><br>}

Attributing Users

The two methods above, both required by React Native, are parts of the Button SDK that we must expose to JavaScript so that we can associate all Button activity with our users (see this guide for more information).

Button.java

public class Button extends ReactContextBaseJavaModule {<br><br> ...<br><br> @ReactMethod<br> public void setUserIdentifier(final String userId){<br> com.usebutton.sdk.Button.getButton(getReactApplicationContext()).setUserIdentifier(userId);<br> }<br><br> @ReactMethod<br> public void logout(){<br> com.usebutton.sdk.Button.getButton(getReactApplicationContext()).logout();<br> }<br><br>}

As you can see, this is pretty simple. To expose a method to JavaScript, a Java method must be annotated using @ReactMethod and the return type must be void, then parameters can be received from JavaScript (see final String userId).

One important thing to note is that each JavaScript type will be converted into its Java equivalent. You can see the full list here.

Server-Side Order Reporting

In order to report conversions, your approach will depend on how you're planning to use Button in your app. For us, we found this to be the best way to prepare our app for server-side order reporting:

1) Getting the Button referrer token from the SDK

Because the React Native bridge is asynchronous, the only way to pass a result to JavaScript is by using callbacks, or, even better, Promises, which can simplify your code, especially when using ES2016's async/await syntax. As the official React Native docs say, "When the last parameter of a bridged native method is a Promise, its corresponding JS method will return a JS Promise object."

Button.java

public class Button extends ReactContextBaseJavaModule {<br><br> ...<br><br> @ReactMethod<br> public void getButtonRef(final Promise callback){<br> try{<br> String ref = com.usebutton.sdk.Button.getButton(getReactApplicationContext()).getReferrerToken();<br><br> if(ref != null &amp;&amp; !ref.isEmpty()){<br> callback.resolve(ref);<br> }else{<br> callback.reject("getButtonRefError", "button ref is null or empty");<br> }<br><br> }catch (Exception e){<br> callback.reject("getButtonRefError", e.getMessage());<br> }<br> }<br><br>}

MyJavascriptClass.js

'use strict';<br><br>import React from 'react';<br><br>import {<br> NativeModules,<br>} from 'react-native';<br><br>const Button = NativeModules.Button;<br><br>export default class MyJavascriptClass {<br><br> setUserId(userId) {<br> Button.setUserIdentifier(userId);<br> },<br><br> userDidLogout() {<br> Button.logout();<br> }<br><br> async getButtonRef(){<br> try{<br> const data = await Button.getButtonRef();<br> if (data){<br> //You might want to send the value of "data" to your backend.<br> }<br> }catch(e){<br> console.log(e);<br> }<br> }<br><br>};

2) Sending it to our backend server for API reporting

Since this post is strictly related to the Android / React Native integration, we won't talk about the server-side aspect here. But you can learn more about it in this guide.

Troubleshooting

If you're getting errors after including the SDK in your build.gradle file, you might want to check the count of available methods in your entire application. Once you go over the limit of 65k, you may need to enable MultiDex.

If you can't figure out what's going on, get in touch with Button Support, who we've found to be really helpful, by sending an email to support@useubutton.com.

Conclusion

Once you wrap your head around Native Modules and their interaction with the JavaScript world, you'll see that this is all pretty straight forward.

If you have a React Native iOS app, you might want to review this guide, as the approach is very similar.

This article was written by Bruno Barbieri and Iveta Lacane from delivery.com.