RN 與原生通訊(Android篇)

iceCola7發表於2019-04-21

一、RN 呼叫安卓程式碼(簡單的實現方式)

RN 呼叫 android 程式碼大致分為以下幾個步驟:

1、用android studio 開啟一個已經建立好的 RN 專案;

2、建立一個類 CommonModule 繼承自 ReactContextBaseJavaModule ,並重寫 getName() 方法,在該類中我們要暴露一些方法供 RN 呼叫;

class CommonModule(private val reactContext: ReactApplicationContext)
    : ReactContextBaseJavaModule(reactContext) {
}
複製程式碼
  • 實現 getName() 方法,改方法用來返回 RN 程式碼需要尋找的類的名稱;
override fun getName(): String {
    // 一定要有名字 RN程式碼要通過名字來呼叫該類的方法
    return "CommonModule"
}
複製程式碼
  • 建立暴露給 RN 呼叫的方法,並用 @ReactMethod 註解修飾;
/**
 * 加上 @ReactMethod 註解是為了暴露給RN呼叫的方法;
 *
 * 方法不能返回值,因為被呼叫的原生程式碼是非同步的,原生程式碼執行結束之後只能通過回撥函式或者傳送訊息給RN
 */
@ReactMethod
fun rnCallNative(msg: String) {
    // 這個方法是說彈出一個彈窗到介面
    Toast.makeText(reactContext, msg, Toast.LENGTH_LONG).show()
}
複製程式碼

3、建立類 CommonPackage 實現介面 ReactPackage 包管理器,並把第2步中建立好的 CommonModule 類新增進來;

class CommonPackage : ReactPackage {
    override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
        val list = ArrayList<NativeModule>()
        list.add(CommonModule(reactContext))
        return list
    }
    override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
        return emptyList()
    }
}
複製程式碼

4、將建立好的 CommonPackage 包管理器新增到 ReactPackage 列表中;也就是在 ReactNativeActivity 中的 onCreate 方法中新增:

class ReactNativeActivity : AppCompatActivity(), DefaultHardwareBackBtnHandler {
    private var mReactRootView: ReactRootView? = null
    private var mReactInstanceManager: ReactInstanceManager? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val list = mutableListOf<ReactPackage>()
        list.add(MainReactPackage()) // 預設
        list.add(CommonPackage()) // 自定義Package

        mReactRootView = ReactRootView(this)
        mReactInstanceManager = ReactInstanceManager.builder()
            .setApplication(application)
            .setCurrentActivity(this)
            //.setBundleAssetName("index.android.bundle")
            .setJSBundleFile(CodePush.getJSBundleFile())// ! 此處為codePush載入JsBundle方式,預設為.setBundleAssetName("index.android.bundle")
            .setJSMainModulePath("index") // ! 注意這裡的index指向入口的js檔案
            //.addPackage(MainReactPackage())
            .addPackages(list) // ! 此處為擴充套件Packages,預設為.addPackage(new MainReactPackage())
            .setUseDeveloperSupport(BuildConfig.DEBUG)
            .setInitialLifecycleState(LifecycleState.RESUMED)
            .build()

        // 注意這裡的 rn_sample 必須對應“index.js”中的 “AppRegistry.registerComponent()”的第一個引數
        mReactRootView?.startReactApplication(mReactInstanceManager, "rn_sample", null)
        setContentView(mReactRootView)
    }
	...
}
複製程式碼

5、在 RN 程式碼中用 NativeModules 元件去呼叫原生模組;

  • 匯入元件,設定方法呼叫原生方法;
import {Alert, Button, NativeModules, StyleSheet, View} from 'react-native';
const commonModule = NativeModules.CommonModule;
function callAndroid() {
    commonModule.rnCallNative('RN 呼叫 Android 原生~~');
}
複製程式碼
  • render 方法裡設定 button 的點選事件直接呼叫自定義方法 callAndroid 即可;
render() {
    return (
        <View style={styles.container}>
            <Button title='call_android' onPress={callAndroid}/>
        </View>
    );
}
複製程式碼

到此,基本的 RN 呼叫安卓原生程式碼的方式就得以實現。

二、RN 用 Promise 機制與安卓原生程式碼通訊

在原生程式碼 CommonModule 類中建立橋接方法,當橋接的方法最後一個引數是 Promise 物件,那麼該方法就會返回一個JSPromise 物件給對應的 JS 方法。

1、首先需要在 CommonModule 中定義一個暴露給 RN 的方法,並且要用 @ReactMethod 標識;

@ReactMethod
fun rnCallNativePromise(msg: String, promise: Promise) {
    Toast.makeText(reactContext, msg, Toast.LENGTH_LONG).show()
    val componentName = name
    promise.resolve(componentName)
}
複製程式碼

2、在 RN 程式碼中也是需要用 NativeModules 元件呼叫原生模組;

import {Alert, Button, NativeModules, StyleSheet, View} from 'react-native';
const commonModule = NativeModules.CommonModule;function callAndroidPromise() {
commonModule.rnCallNativePromise('RN Promise 呼叫 Android 原生~~')
    .then((msg) => {
        Alert.alert('promise 收到訊息', msg)
        console.log("promise 收到訊息", msg)
    })
    .catch((error) => {
        console.log(error)
    })
}
複製程式碼
render() {
    return (
        <View style={styles.container}>
            <Button title='call_android' onPress={callAndroid}/>
            <Button title='call_android_promise' onPress={callAndroidPromise}/>
        </View>
    );
}
複製程式碼

三、RN 用 callback 回撥方式與安卓原生程式碼通訊

1、 同樣也是按照上面的方式,在原生模組中暴露一個橋接的方法給 RN 呼叫,引數傳入一個成功的回撥和一個失敗的回撥;

@ReactMethod
fun rnCallNativeCallback(success: Callback, error: Callback) {
    try {
        success.invoke(100, 200)
    } catch (e: Exception) {
        error.invoke(e.message)
    }
}
複製程式碼

2、在 RN 程式碼中也是需要用 NativeModules 元件呼叫原生模組;

import {Alert, Button, NativeModules, StyleSheet, View} from 'react-native';
const commonModule = NativeModules.CommonModule;function callAndroidCallback() {
    commonModule.rnCallNativeCallback((x, y) => {
        Alert.alert('callback 收到訊息', x + ',' + y)
        console.log('callback 收到訊息', x, y)
    }, (error) => {
        console.log(error)
    })
}
複製程式碼
render() {
    return (
        <View style={styles.container}>
            <Button title='call_android' onPress={callAndroid}/>
            <Button title='call_android_promise' onPress={callAndroidPromise}/>
            <Button title='call_android_callback' onPress={callAndroidCallback}/>
        </View>
    );
}
複製程式碼

最後,RN與安卓原生之間的通訊方式已經介紹完了,如有不對的地方,歡迎指正~~

完整的專案地址:github.com/iceCola7/rn…

相關文章