您的位置:首页 > Web前端 > React

Android原生嵌入React Native 过程中遇见的各种坑

2016-09-01 21:57 477 查看
首先说说情况吧,公司需要原生嵌入ReactNative,迫于需要,要搞起来。看着iOS就搞了20分钟,感觉Android就算麻烦也不能太麻烦的,结果还是自己太年轻了。下面就是我遇到的各种问题,希望对看到的朋友能有帮助

(我用的是ReactNative版本为0.32.0)

1.首先集成的项目目录

我使用的是直接按照react-native init Project 的格式来导入的,也就是说,我的

Android项目目录是跟node_modules是在一个目录下的。

我试过把node_modules集成在Android项目下面的情况,不过没有弄成,所以我换乘来

这种了(有时间可以再试试)

2.第二步就是跟官网和很多教程一样的配置环境了

2.1 在我们Android项目的build.gradle中添加React Native依赖,然后同步,具体代码如下:

compile 'com.facebook.react:react-native:0.32.0'


在此说一下,我也是忘记在哪个大神博客下看的了,如果版本写的是“+”的话,下载的react native版本就是0.20.0的版本,会报一个错,就是版本不符合的错误,“Module 0 is not a registered callable moudle”,这个Google了一下,说是reactnative版本跟服务器的版本不符合,改正了就按着我的步骤三的第一种方法做就可以了,注释掉第三个重写的方法。

2.2紧接着我们需要在项目AndroidManifest.xml中加入网络访问权限

<uses-permission android:name="android.permission.INTERNET" />

还有一个activity就是设置菜单,发现好多里面都没有,我就先放在这里了

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />


2.3 在
android/build.gradle
文件中(注意跟上面的路径不同)加入本地React Native的maven目录(现在React Native的所有组件,无论JS还是Android的预编译包,都是通过npm分发的了):

我是在两个           jcenter()    后面都添加了这个方法

maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}


3.在Activity中添加代码

这里有两种方法都是可以加载的。

第一种:
public class MainActivity extends ReactActivity {

@Override
protected String getMainComponentName() {
return "<span style="font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", "Hiragino Sans GB", 微软雅黑, "WenQuanYi Micro Hei", STHeiti, SimSun, sans-serif; line-height: 2em;">MyAwesomeApp</span><span style="line-height: 2em; font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", "Hiragino Sans GB", 微软雅黑, "WenQuanYi Micro Hei", STHeiti, SimSun, sans-serif;">";</span>
}

@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}

//   @Override
//   protected List<ReactPackage> getPackages() {
//      return Arrays.<ReactPackage>asList(
//               new MainReactPackage()
//       );
}
}


?

由于我使用的是第0.32.0版本的react native,所以运行的时候,最后一个重写的方法会报错的,于是就注释掉了,但是不要担心,getPackages方法写到MainApplication里就可以了

public class MainApplication extends  Application implements ReactApplication {

private Application context;

@Override
public ReactNativeHost getReactNativeHost() {
context = this;
ReactNativeHost host = null;
if (host==null){
host = new ReactNativeHost(context) {
@Override
protected boolean getUseDeveloperSupport() {
return false;
}

@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new IntentReactPackage()
);
}
};
}

return host;
}

}


如果不写的话,会有一个Application强转错误的

第二种,
public class MainActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {

private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//创建一个ReactRootView,把它设置成Activity的主视图
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();
}

//传递一些Activity的生命周期事件到ReactInstanceManager,这是的JavaScript代码可以控制当前用户按下返回按钮的时候作何处理(譬如控制导航切换等等)。如果JavaScript端不处理相应的事件,你的invokeDefaultOnBackPressed方法会被调用。默认情况,这会直接结束你的Activity。
@Override
protected void onPause() {
super.onPause();

if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause();
}
}

@Override
protected void onResume() {
super.onResume();

if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this,this);
}
}

@Override
public void onBackPressed() {
//        mReactInstanceManager.showDevOptionsDialog();
Toast.makeText(this, "dianjialefanhuijian", Toast.LENGTH_SHORT).show();
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}

//我们需要改动一下开发者菜单。默认情况下,任何开发者菜单都可以通过摇晃或者设备类触发,不过这对模拟器不是很有用。所以我们让它在按下Menu键的时候可以显示
@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文件直接就能reload实现了,非常的嗨

4.添加react native包

这就比较简单了,看了好多的文档都是这么写的,也可以直接从init 的项目里拷过来就好,或者按着官方的来就好
$ npm init

跟着步骤回车就好了,然后好像输入个yes

然后就发现有了一个package.json文件

{
"name": "testRN",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "15.3.1",
"react-native": "^0.32.0"
}
}
千万要记住,这个里面的react-native版本一定要和前面gradle的版本一样,不然就出现了那个“Module  0”的版本不一致的错误了,这个错误就看第三步的方法一就好了

然后就是 npm install ,导入react包了

然后就是   

curl -o .flowconfig  https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig

做一下flow配置    虽然现在不知道是为了什么,但是每个人都这么做

5.添加Js代码

import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ToastAndroid

} from 'react-native';

var { NativeModules } = require('react-native');

class MyAwesomeApp extends Component {

constructor(props) {
super(props);

}

render() {
return(
<View >
<Text>哈哈哈哈哈哈哈哈</Text>
</View>
)

}
}

AppRegistry.registerComponent('MyAwesomeApp', () => MyAwesomeApp);


6.运行Demo

开开reactnative的服务器,npm start

在studio中运行demo,会发现,出现一行“哈哈哈哈”

注:可能会出现java.lang.RuntimeException: Could not get BatchedBridge, make sure your bundle is packaged correctly这个错误,Google就有解决方法,就是在命令行里运行

react-native bundle —platform android —dev false —entry-file index.android.js —bundle-output MyYhao/app/src/main/assets/index.android.bundle —sourcemap-output MyYhao/app/src/main/assets/index.android.map —assets-dest MyYhao/app/src/main/res/
react-native bundle —platform android —dev false —entry-file index.android.js —bundle-output MyYhao/app/src/main/assets/index.android.bundle —sourcemap-output MyYhao/app/src/main/assets/index.android.map —assets-dest MyYhao/app/src/main/res/

注意assets的目录,我是在里面直接新建了index.android.bundle和index.android.map两个空文件,然后运行的,会自动往里面写入代码,然后运行就可以了

本人第一次写这些自己的经验,有不足之处,希望大家海涵,因为是后来写的,有些东西可能还是忘记了,如果有碰到什么问题的话,可以直接回复,谢谢

我在自己做的时候,也参考了好多大神的文章,都有很大帮助,他们的文章都在百度的前几个,所以也好找,

谢谢观看
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: