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)
    }
}

Remember to configure the APP_KEY obtained from the Developer Console

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, '====')
})

Last updated