Skip to main content

Example: React Native Integration with Device SDK

Place the Device SDK file

  1. Download the SDK from the Developer Console

  2. Place it in android/app/libs/magic-auth-tool.aar

Configure proguard-rules.pro

-keep class  com.magic.auth.**{*;}

Configure build.gradle

// android/app/build.gradle
dependencies {
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
}

Configure AndroidManifest.xml

// android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xxx.xxx">
<!-- Add address-related read permissions-->
<uses-permission android:name="com.bitboy.info.READ"/>
</manifest>

Create MyAppPackage.kt


// android/app/src/main/java/com/xxx/xxx/MyAppPackage.kt
package com.xxx.xxx // replace your-app-name with your app’s 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 MyAppPackage : ReactPackage {

override fun createViewManagers(
reactContext: ReactApplicationContext
): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()

override fun createNativeModules(
reactContext: ReactApplicationContext
): MutableList<NativeModule> = listOf(DeviceCommunicationModule(reactContext)).toMutableList()
}

Create DeviceCommunicationModule.kt

// android/app/src/main/java/com/ordzgames/profile/DeviceCommunicationModule.kt

package com.xxx.xxx // replace your-app-name with your app’s name

import android.content.Context
import android.os.AsyncTask
import android.content.pm.ApplicationInfo
import android.net.Uri
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import android.util.Log
import android.widget.Toast
import android.database.Cursor
import java.io.BufferedReader
import java.io.FileReader
import com.magic.auth.InitUtil
import android.provider.Settings
import com.facebook.react.bridge.*
import kotlin.Throws
import android.os.Vibrator
import android.os.VibrationEffect
import java.io.InputStreamReader
import android.Manifest
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import java.lang.reflect.Method
import androidx.core.content.ContextCompat

class DeviceCommunicationModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {

override fun getName(): String {
return "DeviceCommunication"
}

private class ReadTask(
private val context: Context,
private val nodePath: String,
private val promise: Promise
) : AsyncTask<Void?, Void?, String?>() {

@Throws(IOException::class)
override fun doInBackground(vararg voids: Void?): String? {
var inputStream: FileInputStream? = null
return try {
inputStream = FileInputStream(nodePath)
val buffer = ByteArray(inputStream.available())
val bytesRead = inputStream.read(buffer)
if (bytesRead > 0) {
String(buffer, Charsets.UTF_8).trim() // Assuming UTF-8 encoding
} else {
"" // or handle no data case as needed
}
} finally {
inputStream?.close()
}
}

override fun onPostExecute(result: String?) {
if (result != null) {
promise.resolve(result)
} else {
promise.reject("READ_FAILED", "Failed to read device node")
}
}
}

private class WriteTask(
private val context: Context,
private val nodePath: String,
private val data: String,
private val promise: Promise
) : AsyncTask<Void?, Void?, Boolean?>() {

@Throws(IOException::class)
override fun doInBackground(vararg voids: Void?): Boolean {
var outputStream: FileOutputStream? = null
return try {
outputStream = FileOutputStream(nodePath)
outputStream.write(data.toByteArray(Charsets.UTF_8)) // Assuming UTF-8 encoding
true
} finally {
outputStream?.close()
}
}

override fun onPostExecute(result: Boolean?) {
if (result == true) {
promise.resolve("success") // Successful write
} else {
promise.reject("WRITE_FAILED", "Failed to write to device node")
}
}
}

private fun getAddressFromProvider(context: Context): String {
val uri = Uri.parse("content://com.bitboy.info/address")
val cursor = context.contentResolver.query(uri, null, null, null, null)
cursor?.moveToNext()
val address = cursor?.getString(0) ?: ""
cursor?.close()
return address
}

@ReactMethod
fun verifyApp(callback: Callback) {
val ret = InitUtil.getReqParam(reactApplicationContext, "Your App Key")
callback.invoke(ret)
}

@ReactMethod
fun getAddress(callback: Callback) {
val context = reactApplicationContext // Access the ReactApplicationContext here
val address = getAddressFromProvider(context)
callback.invoke(address)
}
}

Edit MainApplication.kt

//android/app/src/main/java/com/xxx/xxx/MainApplication.kt

package com.xxx.xxx // replace your-app-name with your app’s name

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.flipper.ReactNativeFlipper

import com.xxx.xxx.DeviceCommunicationModule
import com.facebook.soloader.SoLoader

class MainApplication : Application(), ReactApplication {

override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
// add this
add(MyAppPackage())
}

override fun getJSMainModuleName(): String = "index"

override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}

override val reactHost: ReactHost
get() = getDefaultReactHost(this.applicationContext, reactNativeHost)

override fun onCreate() {
super.onCreate()
SoLoader.init(this, false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager)
}
}

Call Function

import { NativeModules } from 'react-native';

// Get signature data
NativeModules.DeviceCommunication.verifyApp((data) => {
// Failed return: ""
// Successful return: "{ "sign": "", "body": "" }"
try {
const { sign, body } = JSON.parse(data);
} catch (e) {
console.log('Authentication failed')
}
})

// Get wallet address
NativeModules.DeviceCommunication.getAddress(address => {
console.log(address, '====')
})