欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android 原生app嵌入reactnative页面

程序员文章站 2022-05-29 19:58:59
...

话说原生Android app嵌入reactnative页面的网上资料也不少了,而且也不错,但是自己照着做的时候还是问题多多,难道真的是坑太多吗?摸索着最终还是实现了,唉,眼泪哗哗的,先记录一下吧。

第一步让我晕的就是目录结构,看了官方文档一直说项目根目录,结果百度了一下根目录,一哥们说是src的上级目录就是app所在的目录,感觉也是,结果就做下去了,结果就悲催了,折腾了一下午也没搞定,然后看了江清清的文章,这把知道目录了,要在项目的同级目录里面,也就是app的上级目录,src的上上级目录做。这把做下去历经不知道多少劫难,成功啦,开心!但是。。。为毛项目名称一定要是Android啊,这不坑吗,难道我以后的项目名字都有叫这个啊,这显然不行,结果我新建了一个项目,名字随便起的叫ReactNativeOne,结果就报错了:Android project not found. Maybe run react-native android first?,这时候看了网上一哥们的解答,试了一下,确实可以,就是先用android stdio先运行app,首先我们的app是一个原生的,as启动自然没问题。点击绿色小三角运行app启动了,然后运行命令react-native start或者npm start,就可以了,然后跳转RN页面,设置ip和端口,重新加载一下就ok了。下面是demo的主要实现不步骤,和网上有很多雷同,就不一一给出链接了。

1、E:盘下新建目录ReactNativeProject目录,as新建工程ReactNativeOne,一个原生android就出来了,目录如下:

android 原生app嵌入reactnative页面

然后cmd进入到ReactNativeProject目录下面,执行npm init命令,提示输入name的时候就输入reactnativeproject,要小写。其他的一路enter键下去就好了。然后再执行命令npm install --save react react-native,等待一会执行成功,目录结构如下:

android 原生app嵌入reactnative页面

npm install --save react react-native运行完我这提示aaa@qq.com requires a peer of aaa@qq.com but none was installed,打开package.json看看,里面react版本不是16这个,这时候是react-native和react版本不一致问题,一定要解决,否则packager服务起不来,解决办法是输入命令npm i -S aaa@qq.com。再看看package里面react版本就变了。接下来修改package.json文件,package.json里面scripts替换"start": "node node_modules/react-native/local-cli/cli.js start"。然后上图目录里面加入index.android.js文件,代码如下:

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

class Blink extends Component {
  constructor(props) {
    super(props);
    this.state = { showText: true };

    // 每50毫秒对showText状态做一次取反操作
    setInterval(() => {
      this.setState({ showText: !this.state.showText });
    }, 50);
  }

  render() {
    // 根据当前showText的值决定是否显示text内容
    let display = this.state.showText ? this.props.text : ' ';
    return (
      <Text style={styles.bigblue,styles.red}>{display}</Text>
    );
  }
}

class BlinkApp extends Component {
  render() {
    return (
      <View>
        <Blink text='I love to blink' />
        <Blink text='Yes blinking is so great' />
        <Blink text='Why did they ever take this out of HTML' />
        <Blink text='Look at me look at me look at me' />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  bigblue: {
    color: 'blue',
    fontWeight: 'bold',
    fontSize: 30,
  },
  red: {
    color: 'red',
  },
});

AppRegistry.registerComponent('ReactNativeProject', () => BlinkApp);

目录如下:

android 原生app嵌入reactnative页面

接下来修改as工程,打开MainActivity页面,加入一个按钮,然后新建一个ReactNativeActivity页面,按钮跳转到该页面。然后再建立工程,app里面的build.gradle里面导入compile "com.facebook.react:react-native:+" ,这个要在npm install --save react react-native命令后执行,如果顺序反了就在as里面无法正确导入react-native包,可能导入的是老版本的而不是你本地安装的,这个地方要注意一下,否则as就报错了。

gradle里面最低sdk版本要改为至少16,即minSdkVersion16,否则报错。

然后还是在app里面的build.gradle里面的build.gradle里面android{}加入如下代码:

 configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
    }
我这最终代码如下:

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.example.user.reactnativeone"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
    }
}
不然会报如下错误:
Conflict with dependency 'com.google.code.findbugs:jsr305'. 
Resolved versions for app (3.0.0) and test app (2.0.1) differ. 
See http://g.co/androidstudio/app-test-app-conflict for details.

接下来AndroidManifest里面加入权限:

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

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
和DevSettingsActivity声明,不然到时候点击Dev Setting就崩啦

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

最后就是修改DevSettingsActivity里面的代码了:

public class ReactNativeActivity extends Activity implements DefaultHardwareBackBtnHandler {

    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;
    public static int OVERLAY_PERMISSION_REQ_CODE = 1234;

    @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, "ReactNativeProject", null);
        setContentView(mReactRootView);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (!Settings.canDrawOverlays(this)) {
                    // SYSTEM_ALERT_WINDOW permission not granted...
                }
            }
        }
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }

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

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause(this);
        }
    }
    @Override
    protected void onResume() {
        super.onResume();

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

    @Override
    public void onBackPressed() {
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
        } else {
            super.onBackPressed();
        }
    }
}
好了,这下基本上工作完事,准备跑起来吧。

但是...记得开篇说的注意事项了吗,先跑as,模拟器运行处app后,然后在命令行下执行react-native start或者npm start命令。

android 原生app嵌入reactnative页面

模拟器跑出来app后进入android原生页面

android 原生app嵌入reactnative页面

点击按钮进入react-native页面,ctrl+M调出菜单,点击Dev Setting设置ip和端口

android 原生app嵌入reactnative页面

最后as重新运行app就好了,这之前可能要重新运行nmp start命令,最终RN页面如下,是一个带有闪啊闪啊字的页面,截图个静态的页面:

android 原生app嵌入reactnative页面

结束啦。。。并没有。。。

参考网上一个哥们文章,说的有道理,我们为啥要把js和json文件放在工程外面呢,这不合理啊,他们属于工程内部文件啊,那咱把他们移到工程里面,目录如下:

android 原生app嵌入reactnative页面

然后开启packager服务的命令要修改成如下样子了:

android 原生app嵌入reactnative页面

其他的都一样了,至于node_modules文件夹为啥不一起移过去,那样据说会很卡...