Android项目中集成React Native

React Native是非常强大的,但有的时候我们可能并不需要从0开始去开发一个React Native应用,而是需要把它集成到我们现有的Android工程中去,去添加单个的React Native View。本章将主要介绍在原生Android中集成React Native。 

可以参考官方文档中文文档

创建Android工程

新建一个ReactNativeDemo的Android工程作为已有的工程。这部分步骤略过……

集成 React Native

添加JS到App中

进入工程根目录执行以下命令:

npm init
npm install --save react react-native
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
  • 1
  • 2
  • 3
  • 4

npm init命令是根据提示生成 package.json 文件的。

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (ReactNativeDemo) reactnativedemo
version: (1.0.0) 1.0.0
description: react native app demo
entry point: (index.js) index.android.js
test command: 
git repository: 
keywords: 
author: hq
license: (ISC) 
About to write to /home/heqiang/react-native-workspace/ReactNativeDemo/package.json:

{
  "name": "reactnativedemo",
  "version": "1.0.0",
  "description": "react native app demo",
  "main": "index.android.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "hq",
  "license": "ISC"
}


Is this ok? (yes)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

npm install --save react react-native命令是安装React Native依赖的模块,在根目录下生成node_modules。这个下载过程比较慢,如果其他工程下面有,复制过来也是可以的。 
curl用来下载.flowconfig文件

package.json文件中添加下面语句:

"start": "node node_modules/react-native/local-cli/cli.js start"
  • 1

现在的package.json是这样的:

{
  "name": "reactnativedemo",
  "version": "1.0.0",
  "description": "react native app demo",
  "main": "index.android.js",
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "hq",
  "license": "ISC",
  "dependencies": {
    "react": "^15.4.2",
    "react-native": "^0.41.2"
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

创建index.android.js文件:

'use strict';
import React 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}>Hello, World</Text>
      </View>
    )
  }
}
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});
AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

工程配置

在App的build.gradle中加入以下依赖:

dependencies {
 ...
 compile "com.facebook.react:react-native:+" // From node_modules.
}
  • 1
  • 2
  • 3
  • 4

在工程的build.gradle中加入以下配置:

allprojects {
 repositories {
     ...
     maven {
         // All of React Native (JS, Android binaries) is installed from npm
         url "$rootDir/node_modules/react-native/android"
     }
 }
 ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

如果sync过程中出现下面的错误:

Error:Execution failed for task ':app:prepareDebugAndroidTestDependencies'.
  • 1

参考这里,在App的build.gradle中加入:

configurations.all {
    resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
}
  • 1
  • 2
  • 3

AndroidManifest.xml中加入网络权限:

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

添加Native Code

下面将修改原生代码,实现嵌入React Native功能。

方法一

官方文档的做法,首先就是Activity实现DefaultHardwareBackBtnHandler接口:

public class MainActivity extends AppCompatActivity 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, "HelloWorld", null);
        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

方法二

新版本中可以用下面的方法,更简单:

public class MainActivity extends ReactActivity{

    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */
    @Nullable
    @Override
    protected String getMainComponentName() {
        return "HelloWorld"; //这个是在AppRegistry.registerComponent里面注册的。
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

但这个方法需要我们自定义一个Application否则 运行时会报错:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.hq.reactnativedemo/com.android.hq.reactnativedemo.MainActivity}: java.lang.ClassCastException: android.app.Application cannot be cast to com.facebook.react.ReactApplication
  • 1

Application的代码:

public class Application extends android.app.Application implements ReactApplication  {

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

        /**
         * 是否支持开发模式,如果支持就返回true,此时需要打开悬浮窗权限。
         * 不支持的话就返回false
         * @return
         */
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

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

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

还要记得修改AndroidManifest.xml。

运行

根目录运行下面命令:

adb reverse tcp:8081 tcp:8081
npm start
  • 1
  • 2

启动server。 
然后点击Android Studio的运行按钮: 
如果运行时报下面的错误:

02-22 19:18:59.050 24413 24413 E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/com.android.hq.reactnativedemo/lib-main/libgnustl_shared.so" is 32-bit instead of 64-bit
  • 1

可以参考这里或者这里的解决方案,在App的build.gradle里面添加:

    defaultConfig {
        ……
        ndk {
            abiFilters "armeabi-v7a", "x86"
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

再次运行,Hello World界面运行起来了。 
另外记得去应用管理界面打开应用的悬浮窗权限,方便调试。

生成Realease版本

在前面的App运行前,我们需要执行两条命令来启动development server,这在开发环境中可以这么做,但Realese版本这么做肯定是不行的。 
下面就来生成Realease版本。

方法一

app/src/main/中新建assets,根目录下执行下面命令:

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/
  • 1

会在assets目录中生成index.android.bundleindex.android.bundle.meta文件。index.android.bundle文件是所有的React Native js文件打包生成的一个js文件,index.android.bundle.meta中存储的是bundle的sha1值,每次打包都会生成一个meta唯一标识bundle 
再次编译运行App,不用启动启动服务App就可以正常运行了。

方法二

其实也可以通过复制React Native Server里面bundle文件的方法来实现。 
在根目录执行以下命令:

curl "http://localhost:8081/index.android.bundle?platform=android" -o "app/src/main/assets/index.android.bundle"
  • 1

也是可以的。




转载地址:点击打开链接

猜你喜欢

转载自blog.csdn.net/weixin_37852133/article/details/78717013