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

首先说说情况吧,公司需要原生嵌入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两个空文件,然后运行的,会自动往里面写入代码,然后运行就可以了



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


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

谢谢观看

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值