Android—React Native编程
个人博客:haichenyi.com。感谢关注
新公司,新的开始,新的技术
新公司的项目,用到的RN编程,之前完全没有碰到过,遇到新技术,之前完全没有碰到过怎么办?google、百度咯。通过不屑的努力,找到了恋猫月亮 的三篇关于RN的文章。我感觉还是很不错的。
从Android到React Native开发(二、通信与模块实现)
从Android到React Native开发(三、自定义原生控件支持)
可以先浏览上面的第一篇入门,再过来看我这篇文章,我这篇文章就是讲怎么运行一个RN,我只是针对我的项目,把RN的部分提取了出来,上面大佬讲的比较全面。
React Native环境配置
开发工具:android studio。我不知道为什么要换开发工具。AS不好吗?环境还是跟你之前开发的一样配置,不用变
python安装:python官网,下载安装。记得配置环境变量。不用非要按照他那个上面说的去安装。安装完成之后cmd里面敲python然后回车,看到如下界面:

node.js安装:node也是一样,百度安装,配置完环境变量。cmd里面敲 npm -v然后回车,看到如下界面

最后,跑如下命令:
//安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
//React Native的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务。
npm install -g react-native-cli
至此,RN的配置就完成了。记得配置NDK环境,然后就是上你们公司的svn,或者git去down项目下来,应该还会有一个错误,那就是找不到react.gradle的路径,找到你添加依赖的那个gradle,在最上面添加如下代码:
apply from: "../../node_modules/react-native/react.gradle"
这个配置应该是添加greenDao那个是一样的,这样就能找到了react.gradle
项目结构如下:

我用箭头标记了,你down下来的项目,应该是没有node_modules文件夹的,这个文件夹是怎么产生的呢?你在cmd进入你down的项目,就是图片上面的文件目录,跑如下命令即可
npm install
当命令运行完,就可以跑项目了。
React Native项目搭建
同鞋,你有freeStyle吗?有没有用过WebView?WebView就是在你的xml里面新增了一个WebView控件,RN也一样,他的这个控件就是ReactRootView。所以,这个控件哪里来?当然是添加依赖了
//版本号你自己找
compile 'com.facebook.react:react-native:0.50.3'
最终的作用代码就是:
mReactRootView.startReactApplication(mReactInstanceManager, "XXX", null);
这个ReacRootView对象,你可以new出来,也可以写在xml里面findViewById。只要你能获取到这个对象就可以了,然后就是这个方法:
startReactApplication(ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle initialProperties)
三个参数
- ReactInstanceManager reactInstanceManager
- String moduleName
- @Nullable Bundle initialProperties
第一个参数:ReactInstanceManager
就像配置WebView的参数,那些什么配置client允许js弹窗啊,新的页面直接覆盖原来的页面,并不是新建一个页面之类的参数,对应的这里,就是配置ReactInstanceManager
ReactInstanceManagerBuilder builder = ReactInstanceManager.builder();
builder = builder
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index.android");
mReactInstanceManager = builder
.addPackage(new MainReactPackage())
.addPackage(new YzgHDReactPackage())
// .setUseDeveloperSupport(!Global.ISPRD)
.setUseDeveloperSupport(true)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
前面的builder的初始化是必须要写的,setApplication,如果你没有自己写application,那就直接getApplication,如果,你有自己实现application那就传你的application对象。
setBundleAssetName和setJSMainModulePath都是写死的,后面的名字也是写死的。
然后就是添加package,在package里面添加module。这里就是JS和Android相互调用的地方。package里面要实现ReactPackage,在createNativeModules里面去添加moudle
第二个参数:String moduleName
这个moudleName是怎么来的?就是我们前面设置的MoudlePath那个JS里面的。这里的路径应该是index.android.js,是一个js文件,打开之后,最下面有如下代码:
AppRegistry.registerComponent('zzz', () => XXX);
这里的zzz就是我们这里需要传的名字
第三个参数:Bundle initialProperties
这里应该是传一个bundle,传输的数据,传个null就可以了
React Native流程
前面的整个配置都配置完成之后,Android这边只用新建方法,给RN调用就可以了。新建的方法要用@ReactMethod标记。辣么,这个方法新建在哪呢?————Module,就是对应我们前面package里面添加的module。都说RN每个模块是独立的,怎么独立呢?就是这样独立的。每个模块功能对应一个module,每个都有该功能对应的方法。我就拿我这里的UserModule来举个例子
public class UserModule extends IModule implements NoticeListener{
public static final String MODULE_NAME = "User_Module";
private ReactApplicationContext mContext;
public UserModule(ReactApplicationContext reactContext) {
super(reactContext);
this.mContext = reactContext;
}
@Override
public String getName() {
return MODULE_NAME;
}
/**
* 用户登录接口
* @param params
* @param callback
*/
@ReactMethod
public void doLogin(String params, final Callback callback){
HashMap<String,String> map = GsonTool.gson2Map(params);
if(map == null || map.size() <= 0){
callback.invoke(new GsonBuilder().create().toJson(new BaseBean(false,"参数异常")));
return;
}
final String userName = map.get("userName");
final String password = map.get("password");
if(TextUtils.isEmpty(userName) || TextUtils.isEmpty(password)){
callback.invoke(new GsonBuilder().create().toJson(new BaseBean(false,"用户名或密码不能为空")));
return;
}
//登录
new Handler().post(new Runnable() {
@Override
public void run() {
String result = new UserBridge().doLogin(userName,password, Global.DEVICE_ID,Global.APP_VERSION_NAME);
callback.invoke(result);
}
});
}
这里我就粘贴出来了部分代码,module要继承IModule,这个是一个抽象类,他继承ReactContextBaseJavaModule,最主要就是继承它,继承之后,我像说的就是这两个方法,getName()和注解的方法doLogin()。
我们可以看到,这个getName最终返回的是一个User_Module,这个字符串是怎么确定的呢?这个登录的方法名称是怎么确定的呢?
这些东西都是在js里面定义好的,这里是一个登录方法,我们打开登录的js。
PS: 这里应该是通过js去确定我们这边的方法名,并不是通过这里的名称去确定js的。
我就不把JS代码,贴出来了,只贴出伪代码,打开js之后,搜索NativeModules。你应该会搜到类似的代码:
const { User_Module, Shop_Module } = NativeModules;
这里有两个Module,没错,就是两个。我们这里现在只关注User_Module,然后,我们搜索 User_Module,你会看到如下代码:
_onLogIn = () => {
const { username, password } = this.userInfo;
if (username.length <= 0) return this._modal.Alert('请输入用户名');
if (password.length <= 0) return this._modal.Alert('请输入密码');
this._button.setButton(false, '正在登录...');
const params = { userName: username, password };
// 登录
const _dologin = () => {
return new Promise((resolve, reject) => {
User_Module.doLogin(JSON.stringify(params), (...values) => {
const data = Other.callHandle(values) || {};
if (data.status) {
resolve('登录成功');
} else {
reject(data.message);
}
});
});
};
其他的一切,我们都不用管,我们在意的是
User_Module.doLogin(JSON.stringify(params), (...values) => {
const data = Other.callHandle(values) || {};
if (data.status) {
resolve('登录成功');
} else {
reject(data.message);
}
});
上面这个是我的项目里面的js,你们搜到的肯定跟我的不一样,我这里要说的是,怎么确定name的返回值,和注解方法。我们看到了,name就是这里的User_Module,方法就是这里的doLogin,android里面写用@ReactMethod标记,然后就是参数了,这里两个参数,一个是String,json格式的。用ArrayMap存储好key—value之后,转成字符串即可。第二个参数就是callback。android与JS通信,发送数据,就是一个方法
callback.invoke("data")
他需要什么,你就发送什么。上面是RN主动调用Android方法,辣么,Android怎么主动调用RN方法呢?其实也很简单
//发送给RN
if (mReactInstanceManager.getCurrentReactContext() != null) {
mReactInstanceManager.getCurrentReactContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(PUSH_DATA_RN, mqttBean.info);
}
就是获取ReactContext对象,通过调用getJSModule方法,参数传DeviceEventManagerModule.RCTDeviceEventEmitter.class这个类就可以了,然后通过调用emit方法,第一个参数,就是RN规定的方法名称,第二个参数就是需要传给RN的数据。为什么这样写呢?我们再来看看RN那边是怎么写的
DeviceEventEmitter.addListener("push_data_rn",(data)=>{
alert(data)
})
他就是通过这DeviceEventEmitter类添加addListener方法,传两个参数,第一个参数就是我们规定的名称,第二个参数就是一个回调,有一个参数,就是用来接收我们的数据,最后做的处理就是简单的弹窗,当然,这是我自己测试用的,最后RN要怎么坐,就是我要担心的问题了。