React Native平台与Android本地模块之间的调用


有时候APP需要做出React Native平台没有的功能,你也许会想用一些存在的java代码去解决问题,而不是用javascript脚本去去解决问题,或许写一些高性能,多线程的代码,列如图片处理,数据库,或者任何先进的继承
         
        我们设计React Native的目的是尽可能 让你可以写一些真正的原生代码并且可以完全拥有系统的权限的能力,这是一个更加先进的特点,并且我们不希望这是传统开发过程中的一部分,然而它的存在是非常重要的。如果 React Native 不支持你需要的原生特征,那么你应该可以自己构建。

Toast 模块

        首先,我们来写原生模块。一个原生模块的java类通的常继承 ReactContextBaseJavaModule 类,并且实现了 JavaScript 需要实现的方法。我们这里的目的是允许通过使用 JavaScript 调用 ToastAndroid.show('Awesome', ToastAndroid.SHORT);就可以在屏幕上面显示一个短短的 toast 消息。
[html]  view plain  copy
 print ?
  1. package com.facebook.react.modules.toast;  
  2.   
  3. import android.widget.Toast;  
  4.   
  5. import com.facebook.react.bridge.NativeModule;  
  6. import com.facebook.react.bridge.ReactApplicationContext;  
  7. import com.facebook.react.bridge.ReactContext;  
  8. import com.facebook.react.bridge.ReactContextBaseJavaModule;  
  9. import com.facebook.react.bridge.ReactMethod;  
  10.   
  11. import java.util.Map;  
  12.   
  13. public class ToastModule extends ReactContextBaseJavaModule {  
  14.   
  15.   private static final String DURATION_SHORT_KEY = "SHORT";  
  16.   private static final String DURATION_LONG_KEY = "LONG";  
  17.   
  18.   public ToastModule(ReactApplicationContext reactContext) {  
  19.     super(reactContext);  
  20.   }  
  21. }  
     
     ToastModult继承了ReactContextBaseJavaModule这个类需要重写getName 的方法。这个方法就是返回值就是 JavaScript 里面调用 NativeModule 的方法名。在这里我们调用 ToastAndroid 因此我们可以在 JavaScript 里面使用 React.NativeModules.ToastAndroid 来使用这个类。
[html]  view plain  copy
 print ?
  1. @Override  
  2.   public String getName() {  
  3.     return "ToastAndroid";  
  4.   }  
  
     ToastModule里面重写了这个getConstants方法,这个方法会将传递给JavaScript 的常量返回。这个方法不是必须重写,它是非常重要的对于 JavaScript 和 Java 中同步的预定义的关键字的值。
[html]  view plain  copy
 print ?
  1. @Override  
  2.  public Map<String, Object> getConstants() {  
  3.    final Map<String, Object> constants = new HashMap<String,Object>();  
  4.    constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);  
  5.    constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);  
  6.    return constants;  
  7.  }  
    那个英文里面new HashMap<>();是这样写的,我改成了这样new HashMap<String,Object>();
     
     JavaScript d调用的这个方法需要使用 @ReactMethod 这个注解。这个方法的返回值类型是void类型。React Native 的桥接是异步的,因此将一个结果传递给 JavaScript 的唯一方式就是使用回调函数或者调用事件(见下面)。
     
[html]  view plain  copy
 print ?
  1. @ReactMethod  
  2.  public void show(String message, int duration) {  
  3.    Toast.makeText(getReactApplicationContext(), message, duration).show();  
  4.  }  

参数类型


    下面的参数类型是使用 @ReactMethod 注解的方法支持的,并且它们直接对应 JavaScript 中对应的值。
[html]  view plain  copy
 print ?
  1. Boolean -> Bool  
  2. Integer -> Number  
  3. Double -> Number  
  4. Float -> Number  
  5. String -> String  
  6. Callback -> function  
  7. ReadableMap -> Object  
  8. ReadableArray -> Array  

      我们继承ReactContextBaseJavaModule的Java类最后一步就是注册这个模块,我们将在createNativeModules 这个包里面注册。如果这个继承的类没有被注册,那么javaScript 不可调用它
     
[html]  view plain  copy
 print ?
  1. @Override  
  2. public List<NativeModule> createNativeModules(  
  3.                             ReactApplicationContext reactContext) {  
  4.   List<NativeModule> modules = new ArrayList<NativeModule>();  
  5.   
  6.   modules.add(new ToastModule(reactContext));  
  7.   
  8.   return modules;  
  9. }  
     那个英文里面new ArrayList<>();是这样写的,我改成了这样
[html]  view plain  copy
 print ?
  1. new ArrayList<NativeModule>();  
     我们需要用ReactInstanceManager来创建这个包, 。可以看 UIExplorerActivity.java 这个例子。当你初始化一个新工程的时候默认的包是MainReactPackage.java。
[html]  view plain  copy
 print ?
  1. mReactInstanceManager = ReactInstanceManager.builder()  
  2.   .setApplication(getApplication())  
  3.   .setBundleAssetName("AnExampleApp.android.bundle")  
  4.   .setJSMainModuleName("Examples/AnExampleApp/AnExampleApp.android")  
  5.   .addPackage(new AnExampleReactPackage())  
  6.   .setUseDeveloperSupport(true)  
  7.   .setInitialLifecycleState(LifecycleState.RESUMED)  
  8.   .build();  

       为了更方便的从 JavaScript 访问新功能的时,通常会将原生模块包裹在一个 JavaScript 模块里面,不一定这样,但是节省了你的类库的使用者每次都要 pull NativeModules 的不便。这个 JavaScript 文件也为你增加任何 JavaScript 端功能提供了方便。
[html]  view plain  copy
 print ?
  1. /**  
  2.  * @providesModule ToastAndroid  
  3.  */  
  4.   
  5. 'use strict';  
  6.   
  7. /**  
  8.  * This exposes the native ToastAndroid module as a JS module. This has a function 'showText'  
  9.  * which takes the following parameters:  
  10.  *  
  11.  * 1. String message: A string with the text to toast  
  12.  * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or ToastAndroid.LONG  
  13.  */  
  14. var { NativeModules } = require('react-native');  
  15. module.exports = NativeModules.ToastAndroid;  

现在,在JavaScript文件里面你可以类似下面这样调用方法:
[html]  view plain  copy
 print ?
  1. var ToastAndroid = require('ToastAndroid')  
  2. ToastAndroid.show('Awesome', ToastAndroid.SHORT);  
  3.   
  4. // Note: We require ToastAndroid without any relative filepath because  
  5. // of the @providesModule directive. Using @providesModule is optional.  
远不止 Toasts

回调

原生模块也提供了一种特殊的参数-一个回调。在大多数情况下这是给 JavaScript 返回结果使用的。
[html]  view plain  copy
 print ?
  1. public class UIManagerModule extends ReactContextBaseJavaModule {  
  2.   
  3. ...  
  4.   
  5.   @ReactMethod  
  6.   public void measureLayout(  
  7.       int tag,  
  8.       int ancestorTag,  
  9.       Callback errorCallback,  
  10.       Callback successCallback) {  
  11.     try {  
  12.       measureLayout(tag, ancestorTag, mMeasureBuffer);  
  13.       float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);  
  14.       float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);  
  15.       float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);  
  16.       float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);  
  17.       successCallback.invoke(relativeX, relativeY, width, height);  
  18.     } catch (IllegalViewOperationException e) {  
  19.       errorCallback.invoke(e.getMessage());  
  20.     }  
  21.   }  
  22.   
  23. ...  

使用以下方法可以来访问在 JavaScript 里面可以使用:
[html]  view plain  copy
 print ?
  1. UIManager.measureLayout(  
  2.   100,  
  3.   100,  
  4.   (msg) => {  
  5.     console.log(msg);  
  6.   },  
  7.   (x, y, width, height) => {  
  8.     console.log(x + ':' + y + ':' + width + ':' + height);  
  9.   }  
  10. );  
原生模块也提供了一种特殊的参数-一个回调。在大多数情况下这是给 JavaScript 返回结果使用的。


使用以下方法可以来访问在 JavaScript 




原生模块支持只调用一次它的回调。它可以保存这个回调,并且在以后调用。


有一点需要强调的就是,在原生方法完成之后这个回调并不是立即被调用,请记住桥接通信是异步的,因此这个也在运行时循环里面。


线程
原生模块不应该设想有它们将在哪些线程里面被调用,因为目前的任务在以后改变是主要的。如果一个块调用是必须的,那么耗时操作将会被分配到间歇性的工作线程中,并且任何回调将会从这里开始。


给 JavaScript 传递事件
原生模块可以不需要立即被调用就可以给 JavaScript 发送事件。最简单的方式就是使用从 ReactContext 获得的 RCTDeviceEventEmitter,就像下面的代码片段:

[html]  view plain  copy
 print ?
  1. ...  
  2. private void sendEvent(ReactContext reactContext,  
  3.                        String eventName,  
  4.                        @Nullable WritableMap params) {  
  5.   reactContext  
  6.       .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)  
  7.       .emit(eventName, params);  
  8. }  
  9. ...  
  10. WritableMap params = Arguments.createMap();  
  11. ...  
  12. sendEvent(reactContext, "keyboardWillShow", params);  
JavaScript 模块在那时可以通过使用 Subscribable 的 addListenerOn 来注册并且接收事件。

[html]  view plain  copy
 print ?
  1. var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');  
  2. ...  
  3.   
  4. var ScrollResponderMixin = {  
  5.   mixins: [Subscribable.Mixin],  
  6.   
  7.   componentWillMount: function() {  
  8.     ...  
  9.     this.addListenerOn(RCTDeviceEventEmitter,  
  10.                        'keyboardWillShow',  
  11.                        this.scrollResponderKeyboardWillShow);  
  12.     ...  
  13.   },  
  14.   scrollResponderKeyboardWillShow:function(e: Event) {  
  15.     this.keyboardWillOpenTo = e;  
  16.     this.props.onKeyboardWillShow && this.props.onKeyboardWillShow(e);  
  17.   },  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Native提供了一个称为Native Modules的机制,允许您在React Native应用程序中使用原生代码。因此,您可以使用Java或Kotlin编写原生Android代码,并将其与React Native应用程序集成。以下是一些步骤: 1.创建一个新的Android库项目。 2.在您的React Native项目中创建一个新的Native Module。 3.将您的原生代码添加到Android库项目中。 4.编写Java或Kotlin代码来公开原生方法。 5.在React Native Native Module中使用这些方法。 6.构建并运行您的React Native应用程序。 这里是一个简单的例子,说明如何在React Native应用程序中使用原生Android模块: 1.创建一个新的Android库项目 在Android Studio中,选择“File” > “New” > “New Module”。然后选择“Android Library”并按照向导中的说明创建一个新的Android库项目。 2.在您的React Native项目中创建一个新的Native Module 在React Native项目的根目录下,运行以下命令: ``` react-native create-library MyNativeModule ``` 此命令将创建一个名为MyNativeModule的新目录。在此目录中,您可以添加一个名为MyNativeModule.java的文件。 3.将您的原生代码添加到Android库项目中 将您的原生代码复制到Android库项目中的src/main/java目录中。 4.编写Java或Kotlin代码来公开原生方法 在您的Java或Kotlin类中,使用@ReactMethod注释来标记要公开给React Native的原生方法。例如: ``` @ReactMethod public void showToast(String message) { Toast.makeText(getReactApplicationContext(), message, Toast.LENGTH_SHORT).show(); } ``` 5.在React Native Native Module中使用这些方法 在您的React Native应用程序中,导入MyNativeModule并调用其方法。例如: ``` import { NativeModules } from 'react-native'; const { MyNativeModule } = NativeModules; MyNativeModule.showToast('Hello, world!'); ``` 6.构建并运行您的React Native应用程序 在React Native应用程序的根目录中,运行以下命令以构建并运行您的应用程序: ``` react-native run-android ``` 这样,您就可以在React Native应用程序中使用原生Android模块了!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值