刚刚过完年假回来上班,公司并没有特别的任务安排。闲来无事,就莫名的开始了人生第一篇的博客之旅
。本来不想特意将自己get到的东西写到博客上。
一是担心自己的经验不够,写了害怕误人子弟;
二是自己可以随便在云笔记上写自己懂的东西,不必花费很多时间在斟酌字句上,担心有什么疏漏。
好了,既然决定写了就认真的分享下(免得真的误人),自己也再次巩固所学到的,还可以无意之中的帮助别人,何乐不为!
回归正题,对于react-native,去年就开始稍微了解过,尝试写过些小demo,但由于自己的懒惰就没有去尝试性的往下面继续研究了,主要是公司还没用到,自己就想偷个懒。恰巧昨天看到鸿神推送的关于react-native的文章,于是就下定决心开始重拾起来。下面就开始说说个人昨天一天对于rn集成到android项目中实践心得吧,希望各位给出意见!
在android工程的根目录使用npm install -save react react-native下载源文件,最后会生成一个node_modules文件夹(当然也可以拷贝原来的)
拷贝或者下载.flowconfig文件(下载链接https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig),主要是给folw用的,用来做静态代码检查,下载完后放在android的根目录下即可。
配置Android项目react-native依赖库,版本号一定要和本地rn的版本一致

配置react-native本地代码路径,本步骤是制定Android-studio编译react-native时用制定路径下的代码,大致这个意思。这里添加是在根目录下的build.gradle中修改,放在在allPRojects节点下。截图如下:

同步工程在External Libraries看到这个匹配的版本的依赖包就说明成功了。
修改package.json文件,修改信息如下:
{"name": "myapplication","version": "1.0.0","description": "","main": "index.js","scripts": {"start": "node node_modules/react-native/local-cli/cli.js start","bundle-android":"react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output MyApplication/app/src/main/assets/index.android.bundle --sourcemap-output MyApplication/app/src/main/assets/index.android.map --assets-dest MyApplication/app/src/main/res/"},"author": "0","license": "ISC","dependencies": {"react": "^15.3.1","react-native": "^0.33.0"}}name是工程名字字母都小写,scripts一定要根据自己的实际配置不然会报错,dependencies按照自己的版本来修改(最好参照原生的react-native的package.json)第七步:
创建原生安卓类,作为加载rn容器,再将index.android.js(rn的核心代码文件)文件直接放在android项目根目录就行或者自己创建添加如下代码:
import React,{Component} from 'react';import { AppRegistry, StyleSheet, Text, View} from 'react-native';class HelloWorld extends React.Component { render() { return ( <View style={styles.container}> <Text style={styles.hello}>这是React-Native组件</Text> </View> ) }}var styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', backgroundColor:'#ccc', }, hello: { fontSize: 20, color: '#fff', textAlign: 'center', margin: 10, },});//注意这里的reactdemo哦AppRegistry.registerComponent('reactdemo', () => HelloWorld);再创建一个ReactActivitypublic class ReactActivity extends Activity implements DefaultHardwareBackBtnHandler { private ReactRootView mReactRootView; private ReactInstanceManager mReactInstanceManager; private LinearLayout ll; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.myreactdemo); 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(); //reactdemo这个名字要与package.json、以及react-native中index.android.js中的项目名要一致,否则会出错。 mReactRootView.startReactApplication(mReactInstanceManager, "reactdemo", null); ll= (LinearLayout) findViewById(R.id.ll); ll.addView(mReactRootView); } @Override public void invokeDefaultOnBackPressed() { super.onBackPressed(); } @Override protected void onResume() { super.onResume(); if (mReactInstanceManager != null) { mReactInstanceManager.onHostResume(this, this); } } @Override protected void onPause() { super.onPause(); if (mReactInstanceManager != null) { mReactInstanceManager.onHostPause(MyReactActivity.this); } } @Override protected void onDestroy() { super.onDestroy(); if (mReactInstanceManager != null) { mReactInstanceManager.onHostDestroy(MyReactActivity.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); }}再在MainActivity里添加点击事件跳入ReactActivity findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (Build.VERSION.SDK_INT>=23){ if (!Settings.canDrawOverlays(MainActivity.this)){ startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)); return; }else{ } }else{ //绘UI代码,这里android6.0以下的系统可以直接绘出即可 } startActivity(new Intent(MainActivity.this,ReactActivity.class)); } });第八步:
修改AndroidManifest.xml配置文件如下:
<uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/><uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/><activity android:name=".MyReactActivity"/><activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>第九步:
打开cmd进入到android的目录下,运行react-native start ,启动服务,再运行android项目,就可以看见一部分是android原生控件,一部分是rn控件
常见错误
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)解决办法:(老外也遇到了这样的问题https://github.com/facebook/react-native/issues/6152#issuecomment-200759453)在项目下修改以下的文件内容:.gitignore(在该文件里添加排除项,node_modules/ 和 npm-debug.log)app/build.gradle (将 'com.android.support:appcompat-v7:24.2.1' 改为 'com.android.support:appcompat-v7:23.0.1')gradle.properties (在文件末尾添加,android.useDeprecatedNdk=true)红屏问题"Could not get BatchedBridge, make sure your bundle is packaged correctly"解决方法: 主要就只遇到这一个问题, 更改ip和port没有解决了, 后来在package.json中的"scripts"中添加"bundle-android":"react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output 工程名/app/src/main/assets/index.android.bundle --sourcemap-output 工程名/app/src/main/assets/index.android.map --assets-dest 工程名/app/src/main/res/",如果没有assets目录,手动添加下,不过运行时没有效果, 在cmd中手动执行下(去掉命令的工程名如果在根路径下执行命令), assets目录中会多出几个文件, 即可解决这个问题
参考资料:
如何把React Native嵌入到原生android应用中
React Native 集成到已有项目

新闻热点
疑难解答