Link SDKs in React Native
In this guide we will walk you through the steps to integrate the Link SDKs in a React Native context.
You can integrate Enode’s Link SDKs for iOS and Android into your React Native app by making them accessible through the Native Modules system.
Using this guide, you will:
- Ensure that you have the prerequisites to get started
- Expose the Link SDKs in iOS and/or Android as native modules
- Import the exposed native modules into your React Native app
Copy linkPrerequisites
- An existing React Native application
- Existing iOS or Android projects within your React Native app
- A server that calls Link UserAPI with API version
2024-01-01
. You should be able to generate alinkToken
to pass back to your React Native client
Copy linkImplement the iOS native module
Copy linkSet up your Xcode project
Open the iOS project in your React Native app (found under /ios/*.xcworkspace
) in Xcode. Follow the Set up your Xcode project steps from our iOS SDK guide to add LinkKit by extracting the SDK archive, importing the framework, and configuring Bluetooth access.
Copy linkSet up a native module
Copy linkCreate the Swift implementation file
In your main iOS project folder (next to AppDelegate), create a file called LinkUIModule.swift
.
Copy linkCreate a bridging header
At this point, Xcode may prompt you to create a bridging header since you are about to mix Swift and Objective-C (it also may already exist). If it does not exist, manually create one called YourProjectName-Bridging-Header.h
in that same project folder. Ensure the file contains the following:
// YourProjectName-Bridging-Header.h
#import "React/RCTBridgeModule.h"
Copy linkImplement the SDK in Swift
Back in LinkUIModule.swift
, add your implementation:
The bulk of this is the reference implementation from the iOS Link SDK guide alongside some React Native specific details:
// LinkUIModule.swift
import Foundation
import LinkKit
@objc(LinkUIModule)
class LinkUIModule: NSObject {
private var handler: Handler?
@objc
static func requiresMainQueueSetup() -> Bool {
return true
}
@objc
func show(_ token: String, callback: @escaping RCTResponseSenderBlock) {
let vc = RCTPresentedViewController()
self.handler = Handler(linkToken: token) { (code: LinkResultCode, errMsg: String?) in
callback([ code.rawValue, errMsg as Any ])
}
self.handler?.present(from: vc!)
}
}
requiresMainQueueSetup
implemented to returntrue
to tell React Native to initialize the module on the main thread- Adding and invoking a
callback
in thehandler
's completion handler, whose argument will be available in JavaScript - Presenting LinkKit UI from the instance of
RCTPresentedViewController()
Copy linkExpose your Swift implementation to React Native
Create a new file called LinkUIModule.m
and add the following. This makes your Swift implementation available in JavaScript and tells React Native to use the main queue when calling your method since it involves UI operations.
// LinkUIModule.m
#import "React/RCTBridgeModule.h"
@interface RCT_EXTERN_MODULE(LinkUIModule, NSObject)
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXTERN_METHOD(show:(NSString *)token callback:(RCTResponseSenderBlock)callback)
@end
Copy linkImplement the Android native module
Copy linkImport the SDK to your project
Open the Android project in your React Native app (found under /android
), ideally in Android Studio. Follow our Android SDK guide to include the SDK in your app’s build.gradle
. (In a React Native app, you should add the dependency in /android/app/build.gradle
.)
Copy linkConfigure your project
Copy linkSDK versions
If necessary, you may have to increase your compile SDK version and your minimum SDK version. For example, in /android/gradle.properties
set:
android.compileSdkVersion=34
android.minSdkVersion=24
Copy linkKotlin + Java
If your app has a mix of Java and Kotlin, you’ll also need to configure your project to support both. Add this to your /android/app/build.gradle
(after you declare your dependencies
):
apply plugin: "kotlin-android"
Then add this to you /android/build.gradle
's:
dependencies {
...
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
Copy linkStyles
The Link SDK makes use of a few style attributes. Follow the guide for our Android SDK to ensure that you are defining and applying your styles to avoid theming errors.
Copy linkSet up a native module
Copy linkCreate the Kotlin implementation file
Create a new Link UI module file as a Kotlin class within your Android project under /android/app/src/main/java/com/your-app-name/LinkUIModule.kt
. This contains the main native implementation of our Link SDK. Add the following code, which adapts the sample from the main Android SDK guide for React Native:
package com.your-app-name
import android.content.Intent
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Callback
import io.enode.link.LinkKit
const val LINK_UI_REQUEST = 99
class LinkUIModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
private var linkResultCallback: Callback? = null;
private val activityEventListener =
object : BaseActivityEventListener() {
override fun onActivityResult(
activity: Activity?,
requestCode: Int,
resultCode: Int,
intent: Intent?
) {
if (requestCode == LINK_UI_REQUEST) {
if (resultCode == Activity.RESULT_OK) {
linkResultCallback?.invoke("success")
} else {
val errorCode = intent?.getStringExtra(LinkKit.ERROR_CODE)
val errorDetails = intent?.getStringExtra(LinkKit.ERROR_DETAILS)
linkResultCallback?.invoke(errorCode, errorDetails)
}
linkResultCallback = null
}
}
}
override fun getName() = "LinkUIModule"
init {
reactContext.addActivityEventListener(activityEventListener)
}
@ReactMethod
fun show(token: String, callback: Callback) {
val activity = currentActivity
if (activity == null) {
callback.invoke("implementationError", "Unable to get current activity")
return
}
try {
linkResultCallback = callback
val intent = Intent(activity, LinkKit::class.java)
intent.putExtra(LinkKit.INTENT_LINK_TOKEN, token);
activity.startActivityForResult(intent, LINK_UI_REQUEST, null)
} catch (e: RuntimeException) {
callback.invoke("implementationError", "RuntimeException whilst launching LinkKit")
}
}
}
Copy linkExpose your Kotlin implementation to React Native
You need to register your module as a ReactPackage
in order to use it in JavaScript. Create a separate Kotlin class under /android/app/src/main/java/com/your-app-name/LinkUIPackage.kt
and add the following to it:
package com.your-app-name
import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
class LinkUIPackage : ReactPackage {
override fun createViewManagers(
reactContext: ReactApplicationContext
): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()
override fun createNativeModules(
reactContext: ReactApplicationContext
): MutableList<NativeModule> = listOf(LinkUIModule(reactContext)).toMutableList()
}
Next, add this package to the list exposed by React. In your project’s /android/app/src/main/java/com/your-app-name/MainApplication.[kt|java]
file, find where getPackages()
is implemented and be sure to add the Link UI package to it. It should resemble the following (for more information, see React Native docs):
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new LinkUIPackage());
return packages;
}
Copy linkUse the SDKs in React Native
Now that you have exposed the iOS and Android Link SDKs as native modules, you can use them in React Native.
First, create a link session on your server and make sure the resulting linkToken
is available in your React Native app. (For Android, remember to supply an app deeplink as your redirect URI.)
Next, decide where you want to show Link UI and import NativeModules
there:
import { NativeModules } from "react-native";
NativeModules.LinkUIModule
will call native modules you just set up.
The following is a complete example of a LinkUI
React component. If you followed this guide and implemented the same module interface across iOS and Android, the following implementation will be universal across both platforms.
import { Button, View, NativeModules } from "react-native";
export default function LinkUI({ token }) {
const linkUI = NativeModules.LinkUIModule;
return (
<View>
<Button
title="Connect your EV"
onPress={() => {
linkUI.show(token, (code, errMsg) => {
switch (code) {
case "success":
// handle success
console.log("success!");
break;
case "cancelledByUser":
// handle cancellation
console.log("cancelled!");
break;
default:
// handle other error kinds
console.log(
`something went wrong: code=${code}, errMsg=${
errMsg ?? "[n/a]"
}`
);
break;
}
});
}}
/>
</View>
);
}
The callback takes two arguments:
code
: one of string result codes:success
: linking succededmissingLinkToken
: required token parameter was not sentmalformedLinkToken
: thelinkToken
supplied was malformeddismissedViaDismissFunction
: Link UI was dismissed by you (e.g., by callingdismiss()
function on Handler instance on iOS)cancelledByUser
: Link UI was dismissed by the user (e.g., tapping "Close")backendError
: Enode was unable to complete linking due to a service errorearlyExitRequestedFromFrontend
: Link UI itself initiated the closing of the modal
errMsg
(optional): human-readable message string that comes withmalformedLinkToken
,backendError
,earlyExitRequestedFromFrontend
codes
Copy linkTroubleshooting
If you are using Expo with
eas build
and our SwiftPM package, you should ensure that you are running your builds on a server image that runs Xcode 15+. For example, you can add this to your iOS configuration ineas.json
:{ "build": { ... "development": { "ios": { ... "image": "macos-ventura-13.6-xcode-15.2" } }, }, }
When launching LinkSDK on the Android emulator you may run into the issue
Unable to load script. Make sure you are either running a Metro server or that your bundle is packaged correctly for release
or alternatively the issueCLEARTEXT communication to 10.0.2.2 not permitted by network security policy
. This issue happens because Link SDK has a limitation over cleartext communication which blocks the communication between the emulator and your machine. To work around:Create a new file
network_security_config.xml
in theandroid/app/src/main/res/xml/
directory.Add the following contents in the XML file:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">10.0.2.2</domain> </domain-config> </network-security-config>
In
AndroidManifest.xml
, reference this new configuration as follows:<application android:networkSecurityConfig="@xml/network_security_config" ...>
For security reasons, you should not enable cleartext communication in your release builds; only for debug builds.
Copy linkOther ways to integrate
Integrating with the Link SDK for iOS
Integrating with the Link SDK for Android