React Native 原生模块和 JS 模块交互(Android)

1. JS 模块调用原生模块方法
1.1 ReactContextBaseJavaModule
创建一个原生模块  ZanIntentModule  并继承抽象类  ReactContextBaseJavaModule ,同时实现几个方法。
public class ZanIntentModule extends ReactContextBaseJavaModule { public ZanIntentModule (ReactApplicationContext reactContext) { super (reactContext); } @Override public String getName () { return "ZanIntentModule" ; } @Override public Map<String, Object> getConstants () { final Map<String, Object> constants = new HashMap<>(); return constants; } /** * js call native to start activity * * @param toActivityName * @param map */ @ReactMethod public void startActivity (String toActivityName, ReadableMap map) { try { Activity currentActivity = getCurrentActivity(); if (currentActivity != null ) { Class toActivity = Class.forName(toActivityName); Intent intent = getActivityIntent(currentActivity, toActivity, map); currentActivity.startActivity(intent); } } catch (Exception e) { throw new JSApplicationIllegalArgumentException( "Could not open Activity : " + e.getMessage()); } }}
getName()
@Override public String getName () { return "ZanIntentModule" ;}
这个函数用于 返回一个字符串名字,这个名字在 JavaScript 端标记这个模块 。这里我们把这个模块命名为  ZanIntentModule ,这样就可以在 JavaScript 中通过  NativeModules.ZanIntentModule  访问到这个模块。
getConstants()
@Override public Map<String, Object> getConstants () { final Map<String, Object> constants = new HashMap<>(); return constants;}
如果需要在 Java 和 JavaScript 之间定义常量,则要覆盖这个方法,返回需要导出给 JavaScript 使用的常量。
@ReactMethod
要导出一个方法给 JavaScript 使用,Java 方法需要使用注解  @ReactMethod ,方法的返回类型必须为  void 。React Native 的跨语言访问是异步进行的,所以想要给 JavaScript 返回一个值的唯一办法是使用回调函数或者发送事件。
@ReactMethod public void startActivity (String toActivityName, ReadableMap map) { try { Activity currentActivity = getCurrentActivity(); if (currentActivity != null ) { Class toActivity = Class.forName(toActivityName); Intent intent = getActivityIntent(currentActivity, toActivity, map); currentActivity.startActivity(intent); } } catch (Exception e) { throw new JSApplicationIllegalArgumentException( "Could not open Activity : " + e.getMessage()); }}
在 JavaScript 中可以这样调用
NativeModules.ZanIntentModule.startActivity( 'com.danke77.sample.activity.WebViewActivity' , { 'url' : url })
1.2 注册模块
创建一个 Package 类  ZanReactPackage  并实现  ReactPackage ,在  createNativeModules  方法中添加这个模块。
public class ZanReactPackage implements ReactPackage { @Override public List<NativeModule> createNativeModules (ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add( new ZanIntentModule(reactContext)); return modules; } @Override public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } @Override public List<ViewManager> createViewManagers (ReactApplicationContext reactContext) { return Collections.emptyList(); }}
1.3 添加模块
在  Application  中的  ReactNativeHost  实例里  getPackages  方法添加  ZanReactPackage  实例
@Override protected List<ReactPackage> getPackages () { return Arrays.<ReactPackage>asList( new MainReactPackage(), new ZanReactPackage() );}
1.4 回调函数
Callback
Callback 是  com.facebook.react.bridge  中的一个接口,作为 ReactMethod 的一个传参,用来映射 JavaScript 的回调函数(function)。
Callback 接口只定义了一个方法 invoke,invoke 接受多个参数,这个参数必须是  com.facebook.react.bridge  中支持的参数。
@ReactMethod public void login (String name, String password, Callback success, Callback failure) { try { if (TextUtils.isEmpty(name)) { failure.invoke( "name is empty" ); return ; } if (TextUtils.isEmpty(password)) { failure.invoke( "password is empty" ); return ; } if ( new LoginTask().login(name, password)) { success.invoke(name); } else { failure.invoke( "login failure" ); } } catch (Exception e) { e.printStackTrace(); failure.invoke(e.getMessage()); }}
在 JavaScript 中可以这样调用
NativeModules.LoginModule.login( 'name' , 'password' , (name) => { alert(name) }, (err) => { alert(err) })
Promise
Promise 是 ES6 中增加的对于异步编程和回调更加友好的 API。
在  com.facebook.react.bridge  中定义的 Promise 接口,实现了  resolve  和  reject  方法, resolve  用来处理正确结果, reject  用来处理异常。
@ReactMethod public void login (String name, String password, Promise promise) { try { if (TextUtils.isEmpty(name)) { promise.reject( "-1" , "name is empty" ); return ; } if (TextUtils.isEmpty(password)) { promise.reject( "-2" , "password is empty" ); return ; } if ( new LoginTask().login(name, password)) { WritableMap map = Arguments.createMap(); map.putString( "name" , name); promise.resolve(map); } else { promise.reject( "-3" , "login failure" ); } } catch (Exception e) { e.printStackTrace(); promise.reject(e); }}
在 JavaScript 中可以这样调用
NativeModules.LoginModule.login( 'name' , 'password' ) .then( (map) => { alert(map.name) } ) .catch( (code, err) => { alert(err) } )
或者用 async/await 来修饰,以同步方式调用原生模块
async login() { try { var { name } = await NativeModules.LoginModule.login( 'name' , 'password' ) alert(name) } catch (code, err) { alert(err) }}
在原生模块中 Promise 类型的参数必须要放在最后一位,这样 JavaScript 调用的时候才能返回一个 Promise。
2. 原生模块发送事件到 JS 模块
原生模块可以在没有被调用的情况下往 JavaScript 发送事件通知。
protected void sendEvent (ReactContext reactContext, String eventName, @Nullable WritableMap params) { reactContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params);}
发送事件时
WritableMap params = Arguments.createMap();params.putInt( "unread" , unreadCount);sendEvent(getReactApplicationContext(), "onRefreshMessage" , params);
向 JavaScript 模块发送了一个名为  onRefreshMessage  的事件,并携带了  params  作为参数。
JavaScript 模块可以通过使用  DeviceEventEmitter  模块来监听事件
componentDidMount() { DeviceEventEmitter.addListener( 'onRefreshMessage' , this .onUpdateMessage)}componentWillUnmount() { DeviceEventEmitter.removeListener( 'onRefreshMessage' , this .onUpdateMessage)}onUpdateMessage = (e) => { alert(e.unread)}
本文是  慌不要慌  原创,发表于  https://danke77.github.io/ ,请阅读原文支持原创  https://danke77.github.io/2016/12/07/react-native-native-modules-android/ ,版权归作者所有,转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值