ReactNative植入原生应用(windows)
当我们在开发android应用的时候,我们可能只是希望对现有应用中的某些部分用ReactNative进行替换,那么我们就需要在我们的项目中植入ReactNative.
首先我们需要满足如下两个条件:
1.一个已有的,基于gradle构建的Android应用。
2.Node.js。
添加ReactNative依赖
首先在我们的app的build.gradle文件中,添加ReactNative依赖:
compile 'com.facebook.react:react-native:0.20.+'
或者通过如下步骤添加:
AndroidStudio中:File—>Project Structure->app->选择Dependencies->点击+号->选择Library dependency->搜索react-native->选择facebook的react-native的依赖包->点击确定按钮->完成
添加完成后需要在AndroidManifest.xml里增加Internet访问权限:
<uses-permission android:name="android.permission.INTERNET" />
这个仅仅在调试模式从开发服务器加载JavaScript代码的时候用到,因此可以在构建发行包的时候将该权限去掉。
添加原生代码
添加完依赖之后,我们需要添加一些原生代码来启动ReactNative运行库以及让他渲染出东西。首先我们创建一个Activity和一个ReactRootView,然后在里面启动一个React应用并把它设置为Activity的主要内容视图。完整代码如下所示:
package com.hfga.zhangyi.myreact;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
/**
* Created by ZhangYi on 2016/4/8.
*/
public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
mReactRootView.startReactApplication(mReactInstanceManager, "MyAwesomeApp", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onPause();
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onResume(this, this);
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
}
添加JS代码到原生应用
在工程根目录下,运行如下代码:
npm init
该命令会在根目录下创建一个package.json,运行之后会提示输入name,version等信息,如无特殊要求,可直接enter使用默认的即可。
注意:name只能是小写,不能包含大写。
接下来运行如下命令:
npm install --save react-native
该命令会下载react-native所需要的文件,代码等。下载过程中需要梯子,但是在使用梯子下载发现也很容易出错,且速度较慢,我们可以直接下载完整的绿色纯净项目包并拷贝其中的node_modules文件夹到我们的项目根目录中。
注意:因为node_modules文件中层级过多,且有些js文件名字较长,在我们拷贝的过程中有可能出现有些文件不能拷贝,因此在建项目的时候项目所在路径最好不要太长。
拷贝完成后执行如下命令:
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
但是在windows下提示没有curl这个命令,curl是利用URL语法在命令行方式下工作的开源文件传输工具。也就是是说该命令只是下载一个文件,因此我们可以在根目录下新建一个.flowconfig文件,并打开对应的地址:https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig,拷贝其中的所有内容到我们新建的.flowconfig文件中即可。
然后打开之前创建的package.json文件然后在scriptes自断下添加如下内容:
"start": "node node_modules/react-native/local-cli/cli.js start"
注意:其中的test行很有可能在我们运行的时候导致错误,因此可以进行删除。
然后在根目录下新建一个index.android.js文件,并拷贝如下内容,或者可以在该文件中编写自己的页面:
'use strict';
var React = require('react-native');
var {
Text,
View
} = React;
class MyAwesomeApp extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.hello}>Hello, World</Text>
</View>
)
}
}
var styles = React.StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
React.AppRegistry.registerComponent('MyAwesomeApp', () => MyAwesomeApp);
该页面只是输出了一个hello world的TextView。
运行android应用
为了运行我们的应用,首先需要启动开发服务器,只需要在工程目录下运行如下代码:
npm start
或者运行
react-native start
但是在运行的时候有可能提示如下错误:
> myreact@1.0.0 start F:\MyReact
> node node_modules/react-native/local-cli/cli.js start
module.js:327
throw err;
^
Error: Cannot find module 'number-is-nan'
at Function.Module._resolveFilename (module.js:325:15)
at Function.Module._load (module.js:276:25)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
at Object.<anonymous> (F:\MyReact\node_modules\react-native\node_modules\babel-preset-react-native\node_modules\babel-plugin-transform-es2015-modules-commonjs\node_modules\babel-types\node_modules\babel-traverse\node_modules\repeating\node_modules\is-finite\index.js:2:19)
at Module._compile (module.js:409:26)
at Module._extensions..js (module.js:416:10)
at Object.require.extensions.(anonymous function) [as .js] (F:\MyReact\node_modules\react-native\node_modules\babel-register\lib\node.js:138:7)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
这是因为module.js需要的的模块number—is-nan没有找到,我们需要安装对应的模块即可。使用如下命令进行安装:
npm install --save number-is-nan
安装完成后再次运行react-native start命令,如果还有上述错误,按照提示的模块名称进行安装即可。
直到出现如下我们熟悉的界面:
┌────────────────────────────────────────────────────────── ──────────────────┐
│ Running packager on port 8081. │
│ │
│ Keep this packager running while developing on any JS projects. Feel │
│ free to close this tab and run your own packager instance if you │
│ prefer. │
│ │
│ https://github.com/facebook/react-native │
│ │
└────────────────────────────────────────────────────────── ──────────────────┘
Looking for JS files in
F:\MyReact
[22:04:06] <START> Building Dependency Graph
[22:04:06] <START> Crawling File System
[Hot Module Replacement] Server listening on /hot
React packager ready.
[22:06:00] <END> Crawling File System (114099ms)
[22:06:00] <START> Building in-memory fs for JavaScript
[22:06:07] <END> Building in-memory fs for JavaScript (7531ms)
[22:06:07] <START> Building in-memory fs for Assets
[22:06:14] <END> Building in-memory fs for Assets (7067ms)
[22:06:14] <START> Building Haste Map
[22:06:17] <START> Building (deprecated) Asset Map
[22:06:18] <END> Building (deprecated) Asset Map (1114ms)
[22:06:19] <END> Building Haste Map (4642ms)
[22:06:19] <END> Building Dependency Graph (133363ms)
然后运行我们的Android应用,但是在运行之后跳转到我们的React页面,发现应用闪退,AndroidStudio提示如下错误:
java.lang.IllegalAccessError: Method 'void android.support.v4.net.ConnectivityManagerCompat.()' is inaccessible to class 'com.facebook.react.modules.netinfo.NetInfoModule' (declaration of 'com.facebook.react.modules.netinfo.NetInfoModule' appears in /data/app/package.name-2/base.apk)
at com.facebook.react.modules.netinfo.NetInfoModule.(NetInfoModule.java:55)
at com.facebook.react.shell.MainReactPackage.createNativeModules(MainReactPackage.java:62)
at com.facebook.react.ReactInstanceManagerImpl.processPackage(ReactInstanceManagerImpl.java:751)
at com.facebook.react.ReactInstanceManagerImpl.createReactContext(ReactInstanceManagerImpl.java:688)
at com.facebook.react.ReactInstanceManagerImpl.access$600(ReactInstanceManagerImpl.java:84)
如果遇到该错误,需要检查build.gradle文件,将其中的
com.android.support:appcompat-v7:23.2.1
修改为:
com.android.support:appcompat-v7:23.0.1
其他版本的appcompat-v7同理。
最终植入成功,界面显示hello world。