saberstart.1QXO3Q1s3pfN3Qbu1/fN5pb/ahIN+mIOcgSR+mIMbo4MbhnSala.saberend
来源: React Native 十三:植入原生应用 – 彭呈祥 的技术专栏 – 博客频道 – CSDN.NET
版权声明:本文为博主原创文章,未经博主允许不得转载。
由于React并没有假设你其余部分的技术栈—它通常只作为MVC模型中的V存在—它也很容易嵌入到一个并非由React Native开发的应用中。
一、需求
1.一个已有的、基于gradle构建的Android应用;
2.Node.js;
二、准备你的App
1.使用Android Studio创建一个项目,在你的App里的build.gradle文件中,添加React Native依赖:
- compile ‘com.facebook.react:react-native:0.20.+’
2.在你的AndroidManifest.xml里,增加Internet访问权限;
这个仅仅在调试模式从服务器加载JavaScript代码的时候用到,你可以在构建发行包的时候把这条去掉;
- <uses-permission android:name=”android.permission.INTERNET” />
三、添加原生代码
MainActivity.java文件
- package com.example.pengcx.reactnativetest;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.view.KeyEvent;
- import com.facebook.react.LifecycleState;
- import com.facebook.react.ReactInstanceManager;
- import com.facebook.react.ReactRootView;
- import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
- import com.facebook.react.shell.MainReactPackage;
- public class MainActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
- private ReactRootView mReactRootView;
- private ReactInstanceManager mReactInstanceManager;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //创建一个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.onPause();
- }
- }
- @Override
- protected void onResume() {
- super.onResume();
- if (mReactInstanceManager != null) {
- mReactInstanceManager.onResume(this, this);
- }
- }
- @Override
- public void onBackPressed() {
- 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);
- }
- }
到此为止,你的Activity已经可以启动运行一些JavaScrip代码。
四、把JS代码添加到你的应用
在你的工程根目录,运行以下代码:
- pengcx@pengcx-Ubuntu:~/AndroidStudioProjects/ReactNativeTest$ npm init
- 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: (ReactNativeTest) node_modules
- Sorry, node_modules is a blacklisted name.
- name: (ReactNativeTest) react_native
- version: (1.0.0)
- description: reactnative.cn
- entry point: (index.js)
- test command: make test
- git repository:
- keywords:
- author:
- license: (ISC)
- About to write to /home/pengcx/AndroidStudioProjects/ReactNativeTest/package.json:
- {
- “name”: “react_native”,
- “version”: “1.0.0”,
- “description”: “reactnative.cn”,
- “main”: “index.js”,
- “scripts”: {
- “test”: “make test”
- },
- “author”: “”,
- “license”: “ISC”
- }
- Is this ok? (yes) yes
- pengcx@pengcx-Ubuntu:~/AndroidStudioProjects/ReactNativeTest$ npm install –save react-native
- npm WARN package.json react_native@1.0.0 No repository field.
- npm WARN package.json react_native@1.0.0 No README data
- npm WARN peerDependencies The peer dependency react@^0.14.5 included from react-native will no
- npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
- npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
- > bufferutil@1.2.1 install /home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules/react-native/node_modules/ws/node_modules/bufferutil
- > node-gyp rebuild
- make: 进入目录’/home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules /react-native/node_modules/ws/node_modules/bufferutil/build’
- CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
- SOLINK_MODULE(target) Release/obj.target/bufferutil.node
- COPY Release/bufferutil.node
- make: 离开目录“/home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules /react-native/node_modules/ws/node_modules/bufferutil/build”
- npm WARN optional dep failed, continuing fsevents@1.0.12
- > utf-8-validate@1.2.1 install /home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules/react-native/node_modules/ws/node_modules/utf-8-validate
- > node-gyp rebuild
- make: 进入目录’/home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules /react-native/node_modules/ws/node_modules/utf-8-validate/build’
- CXX(target) Release/obj.target/validation/src/validation.o
- SOLINK_MODULE(target) Release/obj.target/validation.node
- COPY Release/validation.node
- make: 离开目录“/home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules /react-native/node_modules/ws/node_modules/utf-8-validate/build”
- > spawn-sync@1.0.15 postinstall /home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules/react-native/node_modules/yeoman-generator/node_modules/cross-spawn/node_modules/spawn-sync
- > node postinstall
- react@0.14.8 node_modules/react
- ├── fbjs@0.6.1 (whatwg-fetch@0.9.0, ua-parser-js@0.7.10, loose-envify@1.1.0, promise@7.1.1, core-js@1.2.6)
- └── envify@3.4.0 (through@2.3.8, jstransform@10.1.0)
- react-native@0.25.1 node_modules/react-native
- ├── regenerator-runtime@0.9.5
- ├── react-clone-referenced-element@1.0.1
- ├── absolute-path@0.0.0
- ├── progress@1.1.8
- ├── stacktrace-parser@0.1.3
- ├── base64-js@0.0.8
- ├── graceful-fs@4.1.4
- ├── event-target-shim@1.1.1
- ├── wordwrap@1.0.0
- ├── react-timer-mixin@0.13.3
- ├── immutable@3.7.6
- ├── semver@5.1.0
- ├── image-size@0.3.5
- ├── opn@3.0.3 (object-assign@4.1.0)
- ├── bser@1.0.2 (node-int64@0.4.0)
- ├── json-stable-stringify@1.0.1 (jsonify@0.0.0)
- ├── Debug@2.2.0 (ms@0.7.1)
- ├── temp@0.8.3 (os-tmpdir@1.0.1, rimraf@2.2.8)
- ├── chalk@1.1.3 (escape-string-regexp@1.0.5, supports-color@2.0.0, ansi-styles@2.2.1, strip-ansi@3.0.1, has-ansi@2.0.0)
- ├── source-map@0.4.4 (amdefine@1.0.0)
- ├── mkdirp@0.5.1 (minimist@0.0.8)
- ├── rebound@0.0.13
- ├── optimist@0.6.1 (wordwrap@0.0.3, minimist@0.0.10)
- ├── worker-farm@1.3.1 (xtend@4.0.1, errno@0.1.4)
- ├── promise@7.1.1 (asap@2.0.3)
- ├── node-haste@2.9.6 (throat@2.0.2, denodeify@1.2.1)
- ├── sane@1.3.4 (fb-watchman@1.9.0, watch@0.10.0, minimist@1.2.0, exec-sh@0.2.0, minimatch@0.2.14, walker@1.0.7)
- ├── yargs@3.32.0 (y18n@3.2.1, camelcase@2.1.1, decamelize@1.2.0, window-size@0.1.4, cliui@3.2.0, string-width@1.0.1, os-locale@1.4.0)
- ├── node-fetch@1.5.2 (is-stream@1.1.0, encoding@0.1.12)
- ├── art@0.10.1
- ├── json5@0.4.0
- ├── uglify-js@2.6.2 (async@0.2.10, uglify-to-browserify@1.0.2, source-map@0.5.6, yargs@3.10.0)
- ├── connect@2.30.2 (cookie@0.1.3, utils-merge@1.0.0, cookie-signature@1.0.6, pause@0.1.0, on-headers@1.0.1, fresh@0.3.0, parseurl@1.3.1, response-time@2.3.1, vhost@3.0.2, basic-auth-connect@1.0.0, bytes@2.1.0, cookie-parser@1.3.5, content-type@1.0.2, depd@1.0.1, qs@4.0.0, method-override@2.3.5, connect-timeout@1.6.2, serve-favicon@2.3.0, http-errors@1.3.1, morgan@1.6.1, express-session@1.11.3, type-is@1.6.12, finalhandler@0.4.0, multiparty@3.3.2, serve-static@1.10.2, csurf@1.8.3, errorhandler@1.4.3, compression@1.5.2, body-parser@1.13.3, serve-index@1.7.3)
- ├── jstransform@11.0.3 (object-assign@2.1.1, base62@1.1.1, esprima-fb@15001.1.0-dev-harmony-fb, commoner@0.10.4)
- ├── module-deps@3.9.1 (browser-resolve@1.11.1, through2@1.1.1, inherits@2.0.1, defined@1.0.0, xtend@4.0.1, duplexer2@0.0.2, parents@1.0.1, concat-stream@1.4.10, readable-stream@1.1.14, subarg@1.0.0, JSONStream@1.1.1, stream-combiner2@1.0.2, resolve@1.1.7, detective@4.3.1)
- ├── babel-plugin-external-helpers@6.8.0 (babel-runtime@6.6.1)
- ├── babel-register@6.8.0 (path-exists@1.0.0, home-or-tmp@1.0.0, source-map-support@0.2.10, babel-runtime@6.6.1)
- ├── babel-polyfill@6.8.0 (babel-regenerator-runtime@6.5.0, babel-runtime@6.6.1)
- ├── babel-types@6.8.1 (to-fast-properties@1.0.2, esutils@2.0.2, babel-traverse@6.8.0, babel-runtime@6.6.1)
- ├── babel-core@6.8.0 (slash@1.0.0, path-exists@1.0.0, shebang-regex@1.0.0, babel-template@6.8.0, path-is-absolute@1.0.0, babel-messages@6.8.0, babel-helpers@6.8.0, private@0.1.6, convert-source-map@1.2.0, babel-code-frame@6.8.0, source-map@0.5.6, minimatch@2.0.10, babel-generator@6.8.0, babel-traverse@6.8.0, babel-runtime@6.6.1)
- ├── babylon@6.8.0 (babel-runtime@6.6.1)
- ├── lodash@3.10.1
- ├── joi@6.10.1 (topo@1.1.0, isemail@1.2.0, hoek@2.16.3, moment@2.13.0)
- ├── fbjs@0.7.2 (ua-parser-js@0.7.10, loose-envify@1.1.0, isomorphic-fetch@2.2.1, core-js@1.2.6)
- ├── babel-preset-react-native@1.7.0 (babel-plugin-transform-es2015-template-literals@6.8.0, babel-plugin-transform-flow-strip-types@6.8.0, babel-plugin-transform-es2015-for-of@6.8.0, babel-plugin-check-es2015-constants@6.8.0, babel-plugin-transform-es2015-destructuring@6.8.0, babel-plugin-transform-class-properties@6.8.0, babel-plugin-transform-es2015-arrow-functions@6.8.0, babel-plugin-syntax-jsx@6.8.0, babel-plugin-syntax-flow@6.8.0, babel-plugin-transform-es2015-spread@6.8.0, babel-plugin-syntax-class-properties@6.8.0, babel-plugin-syntax-async-functions@6.8.0, babel-plugin-transform-react-display-name@6.8.0, babel-plugin-transform-es2015-shorthand-properties@6.8.0, babel-plugin-transform-object-assign@6.8.0, babel-plugin-transform-es2015-function-name@6.8.0, babel-plugin-transform-object-rest-spread@6.8.0, babel-plugin-transform-es2015-modules-commonjs@6.8.0, babel-plugin-transform-es2015-computed-properties@6.8.0, babel-plugin-transform-react-jsx@6.8.0, babel-plugin-transform-es2015-block-scoping@6.8.0, babel-plugin-transform-es2015-parameters@6.8.0, babel-plugin-transform-es2015-classes@6.8.0, babel-plugin-syntax-trailing-function-commas@6.8.0, babel-plugin-transform-regenerator@6.8.0, babel-plugin-react-transform@2.0.2)
- ├── react-transform-hmr@1.0.4 (global@4.3.0, react-proxy@1.1.8)
- ├── yeoman-environment@1.6.1 (escape-string-regexp@1.0.5, log-symbols@1.0.2, text-table@0.2.0, untildify@2.1.0, diff@2.2.2, globby@4.0.0, mem-fs@1.1.3, inquirer@1.0.2, grouped-queue@0.3.2, lodash@4.12.0)
- ├── core-js@2.4.0
- ├── fbjs-scripts@0.4.0 (object-assign@4.1.0, through2@2.0.1, gulp-util@3.0.7, core-js@1.2.6, babel@5.8.38)
- ├── ws@0.8.1 (options@0.0.6, ultron@1.0.2, bufferutil@1.2.1, utf-8-validate@1.2.1)
- └── yeoman-generator@0.20.3 (detect-conflict@1.0.0, read-chunk@1.0.1, path-exists@1.0.0, yeoman-welcome@1.0.1, path-is-absolute@1.0.0, async@1.5.2, mime@1.3.4, text-table@0.2.0, user-home@2.0.0, xdg-basedir@2.0.0, class-extend@0.1.2, dargs@4.1.0, istextorbinary@1.0.2, nopt@3.0.6, diff@2.2.2, run-async@0.1.0, shelljs@0.5.3, yeoman-assert@2.2.1, cli-table@0.3.1, through2@2.0.1, glob@5.0.15, findup-sync@0.2.1, rimraf@2.5.2, mem-fs-editor@2.2.0, underscore.string@3.3.4, sinon@1.17.4, dateformat@1.0.12, pretty-bytes@2.0.1, github-username@2.1.0, html-wiring@1.2.0, download@4.4.3, inquirer@0.8.5, gruntfile-editor@1.2.0, cross-spawn@2.2.3)
- pengcx@pengcx-Ubuntu:~/AndroidStudioProjects/ReactNativeTest$ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
- 100 2654 100 2654 0 0 1522 0 0:00:01 0:00:01 –:–:– 1521
上面的代码会创建一个node模块,然后react-native作为npm依赖添加。现在打开新创建的package.json文件然后在scripts字段添加如下内容:
- “start”: “node node_modules/react-native/local-cli/cli.js start”
复制并粘贴下面这段代码到你的工程根目录下面的index.android.js—这是一个简单的React Native应用:
android.android.js文件
- ‘use strict’;
- var React = require(‘react’);
- var ReactNative = require(‘react-native’);
- var {
- Text,
- View,
- StyleSheet,
- AppRegistry
- } = ReactNative;
- class MyAwesomeApp 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(‘MyAwesomeApp’, () => MyAwesomeApp);
五、运行你的应用
为了运行你的应用,首先要启动开发服务器。只需要在你的工程目录运行这段代码:
- pengcx@pengcx-Ubuntu:~/AndroidStudioProjects/ReactNativeTest$ npm start
- ┌────────────────────────────────────────────────────────────────────────────┐
- │ Running packager on port 8081. │
- │ │
- │ Keep this packager running while developing on any JS projects. Feel │
- │ free to close this tab and run your own packager instance if you │
- │ prefer. │
- │ │
- │ https://github.com/facebook/react-native │
- │ │
- └────────────────────────────────────────────────────────────────────────────┘
- Looking for JS files in
- /home/pengcx/AndroidStudioProjects/ReactNativeTest
- [02:17:41] <START> Building Dependency Graph
- [02:17:57] <START> Crawling File System
- [Hot Module Replacement] Server listening on /hot
- React packager ready.
六、应用程序运行如下:
现在来构建和运行你的Android应用(譬如./gradlew installDebug)。一旦启动了React Native制作的Activity,它应该会从开发服务器加载代码并显示:
提示1:在完成上面的操作步骤之后,启动程序获取JS代码的时候,程序会崩溃,报错如下:
05-12 02:52:21.440 3992-4020/com.example.pengcx.reactnativetest E/libEGL: cache file failed CRC check
05-12 02:52:21.502 3992-4019/com.example.pengcx.reactnativetest E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.pengcx.reactnativetest, PID: 3992
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalAccessError: Method ‘void android.support.v4.net.ConnectivityManagerCompat.<init>()’ is inaccessible to class ‘com.facebook.react.modules.netinfo.NetInfoModule’ (declaration of ‘com.facebook.react.modules.netinfo.NetInfoModule’ appears in /data/app/com.example.pengcx.reactnativetest-1/base.apk)
at com.facebook.react.modules.netinfo.NetInfoModule.<init>(NetInfoModule.java:55)
at com.facebook.react.shell.MainReactPackage.createNativeModules(MainReactPackage.java:67)
at com.facebook.react.ReactInstanceManagerImpl.processPackage(ReactInstanceManagerImpl.java:793)
at com.facebook.react.ReactInstanceManagerImpl.createReactContext(ReactInstanceManagerImpl.java:730)
at com.facebook.react.ReactInstanceManagerImpl.access$600(ReactInstanceManagerImpl.java:91)
at com.facebook.react.ReactInstanceManagerImpl$ReactContextInitAsyncTask.doInBackground(ReactInstanceManagerImpl.java:184)
at com.facebook.react.ReactInstanceManagerImpl$ReactContextInitAsyncTask.doInBackground(ReactInstanceManagerImpl.java:169)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
处理:该问题应该是引用的react的版本问题,而且目前Maven库中没有最新版本的React Native版本,引用项目根目录下的最新版本:
修改app下的build.gradle文件
compile ‘com.android.support:appcompat-v7:23.0.1’
compile ‘com.facebook.react:react-native:+’
修改项目根目录下的build.gradle文件
allprojects {
repositories {
mavenLocal()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url “$projectDir/node_modules/react-native/android”
}
}
}