Android项目集成RN系列:修改端口号 / 离线包 / 消息
2018-11-18 本文已影响6人
闲庭
- 手动修改React Native端口号
- 将RN项目打包成离线包
- RN与Android原生的消息通信
不清楚Android项目如何集成RN,见【简述RN集成到Android原生项目】
1. 手动修改React Native端口号
-
修改React Native Server端口号
运行一个React Native项目的时候,React Native会启动一个默认端口号为8081的本地服务,该8081的服务就是React Native项目的一个本地服务器,用于提供JSBundle包和一些静态资源。- 临时修改Server端口号
通过cmd执行yarn start --port=8082
或者npm run start --port=8082
. - 永久修改Server端口号
在你的项目名称/node_modules/react-native/local-cli/server/server.js
找到server.js
文件,打开后找到module.exports -> options -> command: '--port [number]'
修改对应的default的值。
修改前:
修改后:{ command: '--port [number]', parse: (val: string) => Number(val), default: (config: ConfigT) => config.server.port, }
{ command: '--port [number]', parse: (val: string) => Number(val), default: 8082, }
- 临时修改Server端口号
-
修改对应集成RN的Android 项目的端口号
- 方案一:代码中在application或者主activity中做如下设置:
@Override public void onCreate() { super.onCreate(); SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); mPreferences.edit().putString("debug_http_host","localhost:8082").commit(); }
- 方案二:React Native 会给 Android手机或者是虚拟机安装一个软件,就是你的软件,首先我们先打开这个软件,报错页面摇晃手机显示菜单,找到
Dev Settings
=> 然后找到Debug server host & port for device
=> 然后输入电脑的ip地址和端口 , 点击返回 => 页面是空白,再次点击摇一摇,选择Reload JS
程序就显示出来了。
- 方案一:代码中在application或者主activity中做如下设置:
2. 打离线包,手动生成index.android.bundle 文件保存到assets 文件夹下或者本地存储文件夹中。
react-native bundle --entry-file index.android.js --platform android --dev false --bundle-output ./app/src/main/assets/index.android.bundle --assets-dest ./app/src/main/res/
- --platform:平台
- --dev:开发模式
- --entry-file:条目文件
- --bundle-output:bundle文件生成的目录
- --assets-dest:资源文件生成的目录
备注:
react-native bundle --entry-file index.js --platform android --dev false --bundle-output ./app/src/main/assets/index.android.bundle --assets-dest ./app/src/main/res/
不同业务对应的--entry-file文件不一样(有的是index.js,有的是index.android.js),打包时填写正确的入口文件名,并且--bundle-output输出的文件名也需要根据业务区分。
查看打包命令
react-native bundle -h
3. RN与Android原生的消息通信
-
创建
MyNativeModule.java
package com.liujc.rnappdemo.hybride; import android.app.Activity; import android.content.Intent; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.modules.core.DeviceEventManagerModule; import java.util.HashMap; import java.util.Map; /** * 类名称:MyNativeModule * 创建者:Create by liujc * 描述:原生预留给RN的调用方法 */ public class MyNativeModule extends ReactContextBaseJavaModule { public static final String REACT_NATIVE_CLASSNAME = "MyNativeModule"; private ReactApplicationContext mContext; public static final String EVENT_NAME = "nativeCallRn"; public static final String TAG = "TAG"; public MyNativeModule(ReactApplicationContext reactContext) { super(reactContext); mContext = reactContext; } @Override public String getName() { //返回的这个名字是必须的,在rn代码中需要这个名字来调用该类的方法。 return REACT_NATIVE_CLASSNAME; } //函数不能有返回值,因为被调用的原生代码是异步的,原生代码执行结束之后只能通过回调函数或者发送信息给rn那边。 @ReactMethod public void rnCallNative(String msg){ Toast.makeText(mContext,msg,Toast.LENGTH_SHORT).show(); } @ReactMethod public void startActivityRN(String name, String params) { try { Activity activity = getCurrentActivity(); if (activity != null) { Class toClass = Class.forName(name); Intent intent = new Intent(activity, toClass); intent.putExtra("params", params); activity.startActivity(intent); } } catch (Exception ex) { throw new JSApplicationIllegalArgumentException("不能打开Activity " + ex.getMessage()); } } //后面该方法可以用Linking代替 @ReactMethod public void getDataFromIntent(Callback success, Callback error) { try { Activity currentActivity = getCurrentActivity(); String result = currentActivity.getIntent().getStringExtra("result");//会有对应数据放入 if (!TextUtils.isEmpty(result)) { success.invoke(result); } } catch (Exception ex) { error.invoke(ex.getMessage()); } } /** * Native调用RN * @param msg */ public void nativeCallRn(String msg) { mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(EVENT_NAME,msg); } /** * Callback 方式 * rn调用Native,并获取返回值 * @param msg * @param callback */ @ReactMethod public void rnCallNativeFromCallback(String msg, Callback callback) { String result = "hello RN!Native正在处理你的callback请求"; // .回调RN,即将处理结果返回给RN callback.invoke(result); } /** * Promise * @param msg * @param promise */ @ReactMethod public void rnCallNativeFromPromise(String msg, Promise promise) { Log.e(TAG,"rnCallNativeFromPromise"); String result = "hello RN!Native正在处理你的promise请求" ; promise.resolve(result); } /** * 向RN传递常量 */ @Nullable @Override public Map<String, Object> getConstants() { Map<String,Object> params = new HashMap<>(); params.put("Constant","我是Native常量,传递给RN"); return params; } }
-
创建
MyReactPackage.java
/** * 类名称:MyReactPackage * 创建者:Create by liujc * 描述:RN包管理器 */ public class MyReactPackage implements ReactPackage { public MyNativeModule myNativeModule; @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { myNativeModule = new MyNativeModule(reactContext); List<NativeModule> modules = new ArrayList<>(); //将我们创建NativeModule添加进原生模块列表中 modules.add(myNativeModule); return modules; } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { //该处后期RN调用原生控件或自定义组件时可用到 return Collections.emptyList(); } }
-
将我们创建的
MyReactPackage
添加到我们在AppApplication
中创建的ReactNativeHost
中。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 MyReactPackage() ); } };
-
接下来我们在js文件中如何调用?
'use strict'; import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, NativeModules, View, ToastAndroid, DeviceEventEmitter } from 'react-native'; let title = 'React Native界面'; class reactNative extends Component { /**加载完成*/ componentWillMount() { let result = NativeModules.MyNativeModule.Constant; console.log('原生端返回的常量值为:' + result); } /** * 原生调用RN */ componentDidMount() { DeviceEventEmitter.addListener('nativeCallRn',(msg)=>{ title = "React Native界面,收到数据:" + msg; ToastAndroid.show("发送成功", ToastAndroid.SHORT); }) } /** * RN调用Native且通过Callback回调 通信方式 */ callbackComm(msg) { NativeModules.MyNativeModule.rnCallNativeFromCallback(msg,(result) => { ToastAndroid.show("CallBack收到消息:" + result, ToastAndroid.SHORT); }) } /** * RN调用Native且通过Promise回调 通信方式 */ promiseComm(msg) { NativeModules.MyNativeModule.rnCallNativeFromPromise(msg).then( (result) =>{ ToastAndroid.show("Promise收到消息:" + result, ToastAndroid.SHORT) } ).catch((error) =>{console.log(error)}); } /** * 调用原生代码 */ call_button(){ NativeModules.MyNativeModule.rnCallNative('调用原生方法操作'); } callNative(){ NativeModules.MyNativeModule.startActivityRN('com.liujc.rnappdemo.MyRNActivity','test'); } render() { return ( <View style={styles.container}> <Text style={styles.welcome} > {title} </Text> <Text style={styles.welcome} onPress={this.call_button.bind(this)} > React Native 调用原生方法操作! </Text> <Text style={styles.welcome} //给此处的文字绑定一个事件,其中callNative为要调用的方法名。 onPress={this.callNative.bind(this)}> 跳转MyRNActivity! </Text> <Text style={styles.welcome} onPress={this.callbackComm.bind(this,'callback发送啦')}> Callback通信方式 </Text> <Text style={styles.welcome} onPress={this.promiseComm.bind(this,'promise发送啦')}> Promise通信方式 </Text> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, }); AppRegistry.registerComponent('reactNative', () => reactNative);