惯例这是写在前面的话,周五的时候和同事朋友聊起来写博客这件事,自己在朋友圈吹下的牛逼,无论如何都是要完成的啊,等把博客写完了,奖励自己玩一会儿魔兽,我的小号兽人战士已经10级了,联盟,你们颤抖吧。
react native 和原生平台 android的交互
我们这里从react-natvie 调用原生android的方法,获取原生android的数据
部分开始讲,其中还包括android
对react-native
的回调。
这就是说的互相交互的事,那么我们开始吧!
react-natvie 调用原生android的方法,获取原生android的数据
在react-native
和原生平台API
之间,有一个JavaScript
的桥接层,react-native
就是通过桥接层来和原生的平台进行交互的,其中,这涉及到了两个模块NativeModule
和NativeEventEmitter
。
1.NativeModule
:用于JavaScript
代码调用原生的代码。
2.NativeEventEmitter
:用于原生代码发送消息到JavaScript
代码。
我们可以看一下Animated
下的源码实现:
目录在这里
node_modules\react-native\Libraries\Animated\src\NativeAnimatedHelper.js
它的第一行就是
const NativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
const NativeEventEmitter = require('NativeEventEmitter');
引用了这两个模块,我们再看一下下面是怎么调用的呢?
createAnimatedNode: function(tag: ?number, config: Object): void {
assertNativeAnimatedModule();
NativeAnimatedModule.createAnimatedNode(tag, config);
},
创建一个Animated
动画,是通过调用NativeAnimatedModule.createAnimatedNode(tag, config);
来实现的。
而在android
这里的代码,如果想要能够让react-native
调用到,需要实现三个步骤:
1.写出你想要调用的模块(继承ReactContextBaseJavaModule)
2.把这个模块导出(实现导出接口ReactPackage)
3.把这个模块注册发布(在MainApplication中注册)
那么我们开始吧:
1.写出你想要调用的模块(继承ReactContextBaseJavaModule)
//...
/**
* Created by feiyu on 2018/5/12.
*/
public class CommunicationModule extends ReactContextBaseJavaModule {
private final ReactApplicationContext mReactContext;
public CommunicationModule(ReactApplicationContext reactContext) {
super(reactContext);
this.mReactContext = reactContext;
}
@Override
public String getName() {
//你想要调用的那个模块的名称,实际上就是当前的这个对象
return "Communication";
}
@Nullable
@Override
public Map<String, Object> getConstants() {
HashMap<String,Object> constants = new HashMap<>();
constants.put("systemName","android");
return constants;
}
//我们想要调用的原生的android方法,这个方法可以打开一个activity,同时还可以传递参数过来
@ReactMethod
public void StartActivityFromReactNative(String activityName, String data, Promise promise, Callback callback){
Activity currentActivity = getCurrentActivity();
try{
if(currentActivity != null){
Class<?> toActivity = Class.forName("yourPackageName" +"." +activityName);
Intent intent = new Intent(currentActivity,toActivity);
intent.putExtra("params",data);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//在react native 打开activity
currentActivity.startActivity(intent);
}
promise.resolve(true);
callback.invoke(true);
}catch(ClassNotFoundException e){
throw new JSApplicationIllegalArgumentException("打开activity失败"+e.getMessage());
}
}
}
在这里我们实现了一个必须的方法就是getName
这个方法返回的是我们想要调用的那个模块的名称,也就是当前对象。同时我们想要给react-native
传递一些参数,就实现了getConstants
方法,在这个方法中我们设置了当前平台的名称。我们想要调用一个android
本地的方法,所以我们实现了StartActivityFromReactNative
方法,重要的是我们需要设置@ReactMethod
注解。调用完StartActivityFromReactNative
方法后我们想要知道调用结果呢?我们有两种方式Promise
和Callback
都可以,例如上面的代码。
2.把这个模块导出(实现导出接口ReactPackage)
//...
/**
* Created by feiyu on 2018/5/12.
*/
public class Communication implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new CommunicationModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
public List<Class<? extends JavaScriptModule>> createJSModules(){
return Collections.emptyList();
}
}
上面的这个就是固定模式了,你在实现任意的模块时都可以复制上面的代码,然后把CommunicationModule
换成你的。
3.把这个模块注册发布(在MainApplication中注册)
第三步就非常简单了!
//...
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new Communication()
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
//...
}
最后我们在getPackages
中返回我们的对象就可以了new Communication()
.
react-native 调用android原生
react-native
调用原生平台是基于NativeModules
,调用的方法是NativeModules
.模块名称.接口名称。
原生平台返回数据到react-native
平台是基于回调,回调的原型定义是RCTRResponseSenderBlock(IOS)平台
和com.facebook.react.bridge.CallBack(Android平台)
。
我们想要获取android
平台定义的那个systemName
的话只需要这样:
if(Platform.OS === "android"){
let systemName = NativeModule.Communction.systemName;
}
调用我们定义的那个打开activity
的方法也是同上:
if(Platform.OS === "android"){
NativeModule.Communction.StartActivityFromReactNative("CommunicationActivity",123456);
}
这样就可以了。然后怎么获取到react-native
给传过来的数据呢?在android
的activity
中:
public class CommunicationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_communication);
Intent intent = getIntent();
if(intent != null){
String params = intent.getStringExtra("'params");
Toast.makeText(this,"从react-native中传递过来的数据"+params,Toast.LENGTH_LONG).show();
}
}
}
需要注意的地方:
1.react native
调用android
进行界面跳转时,需要设置FLAG_ACTIVITY_NEW_TASK
标志
2.我们在调用android
的模块时,名称要和getName
的方法一样:
NativeModule.Communction.systemName;
就是Communction
...
到这里react-native
和android
的就Over
了。祝大家周末愉快!
参考书籍:《React Native 移动开发实战》
网友评论