React Native 十三:植入原生应用 – 彭呈祥 的技术专栏 – 博客频道 – CSDN.NET

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依赖:
  1. compile ‘com.facebook.react:react-native:0.20.+’

2.在你的AndroidManifest.xml里,增加Internet访问权限;

这个仅仅在调试模式从服务器加载JavaScript代码的时候用到,你可以在构建发行包的时候把这条去掉;
  1. <uses-permission android:name=”android.permission.INTERNET” />

三、添加原生代码

MainActivity.java文件
  1. package com.example.pengcx.reactnativetest;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.KeyEvent;
  5. import com.facebook.react.LifecycleState;
  6. import com.facebook.react.ReactInstanceManager;
  7. import com.facebook.react.ReactRootView;
  8. import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
  9. import com.facebook.react.shell.MainReactPackage;
  10. public class MainActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
  11.     private ReactRootView mReactRootView;
  12.     private ReactInstanceManager mReactInstanceManager;
  13.     @Override
  14.     protected void onCreate(Bundle savedInstanceState) {
  15.         super.onCreate(savedInstanceState);
  16.         //创建一个ReactRootView,把它设置成Activity的主视图
  17.         mReactRootView = new ReactRootView(this);
  18.         mReactInstanceManager = ReactInstanceManager.builder()
  19.                 .setApplication(getApplication())
  20.                 .setBundleAssetName(“index.android.bundle”)
  21.                 .setJSMainModuleName(“index.android”)
  22.                 .addPackage(new MainReactPackage())
  23.                 .setUseDeveloperSupport(BuildConfig.Debug)
  24.                 .setInitialLifecycleState(LifecycleState.RESUMED)
  25.                 .build();
  26.         mReactRootView.startReactApplication(mReactInstanceManager, “MyAwesomeApp”null);
  27.         setContentView(mReactRootView);
  28.     }
  29.     @Override
  30.     public void invokeDefaultOnBackPressed() {
  31.         super.onBackPressed();
  32.     }
  33.     // 传递一些Activity的生命周期事件到ReactInstanceManager,这是的JavaScript代码可以控制当前用户按下返回按钮的时 候作何处理(譬如控制导航切换等等)。如果JavaScript端不处理相应的事件,你的invokeDefaultOnBackPressed方法会被 调用。默认情况,这会直接结束你的Activity。
  34.     @Override
  35.     protected void onPause() {
  36.         super.onPause();
  37.         if (mReactInstanceManager != null) {
  38.             mReactInstanceManager.onPause();
  39.         }
  40.     }
  41.     @Override
  42.     protected void onResume() {
  43.         super.onResume();
  44.         if (mReactInstanceManager != null) {
  45.             mReactInstanceManager.onResume(thisthis);
  46.         }
  47.     }
  48.     @Override
  49.     public void onBackPressed() {
  50.         if (mReactInstanceManager != null) {
  51.             mReactInstanceManager.onBackPressed();
  52.         } else {
  53.             super.onBackPressed();
  54.         }
  55.     }
  56.     //我们需要改动一下开发者菜单。默认情况下,任何开发者菜单都可以通过摇晃或者设备类触发,不过这对模拟器不是很有用。所以我们让它在按下Menu键的时候可以显示
  57.     @Override
  58.     public boolean onKeyUp(int keyCode, KeyEvent event) {
  59.         if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
  60.             mReactInstanceManager.showDevOptionsDialog();
  61.             return true;
  62.         }
  63.         return super.onKeyUp(keyCode, event);
  64.     }
  65. }

到此为止,你的Activity已经可以启动运行一些JavaScrip代码。

四、把JS代码添加到你的应用
在你的工程根目录,运行以下代码:
  1. pengcx@pengcx-Ubuntu:~/AndroidStudioProjects/ReactNativeTest$ npm init
  2. This utility will walk you through creating a package.json file.
  3. It only covers the most common items, and tries to guess sensible defaults.
  4. See `npm help json` for definitive documentation on these fields
  5. and exactly what they do.
  6. Use `npm install <pkg> –save` afterwards to install a package and
  7. save it as a dependency in the package.json file.
  8. Press ^C at any time to quit.
  9. name: (ReactNativeTest) node_modules
  10. Sorry, node_modules is a blacklisted name.
  11. name: (ReactNativeTest) react_native
  12. version: (1.0.0)
  13. description: reactnative.cn
  14. entry point: (index.js)
  15. test command: make test
  16. git repository:
  17. keywords:
  18. author:
  19. license: (ISC)
  20. About to write to /home/pengcx/AndroidStudioProjects/ReactNativeTest/package.json:
  21. {
  22.   “name”: “react_native”,
  23.   “version”: “1.0.0”,
  24.   “description”: “reactnative.cn”,
  25.   “main”: “index.js”,
  26.   “scripts”: {
  27.     “test”: “make test”
  28.   },
  29.   “author”: “”,
  30.   “license”: “ISC”
  31. }
  32. Is this ok? (yes) yes
  33. pengcx@pengcx-Ubuntu:~/AndroidStudioProjects/ReactNativeTest$ npm install –save react-native
  34. npm WARN package.json react_native@1.0.0 No repository field.
  35. npm WARN package.json react_native@1.0.0 No README data
  36. npm WARN peerDependencies The peer dependency react@^0.14.5 included from react-native will no
  37. npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
  38. npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
  39. > bufferutil@1.2.1 install /home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules/react-native/node_modules/ws/node_modules/bufferutil
  40. > node-gyp rebuild
  41. make: 进入目录’/home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules /react-native/node_modules/ws/node_modules/bufferutil/build’
  42.   CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
  43.   SOLINK_MODULE(target) Release/obj.target/bufferutil.node
  44.   COPY Release/bufferutil.node
  45. make: 离开目录“/home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules /react-native/node_modules/ws/node_modules/bufferutil/build”
  46. npm WARN optional dep failed, continuing fsevents@1.0.12
  47. > utf-8-validate@1.2.1 install /home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules/react-native/node_modules/ws/node_modules/utf-8-validate
  48. > node-gyp rebuild
  49. make: 进入目录’/home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules /react-native/node_modules/ws/node_modules/utf-8-validate/build’
  50.   CXX(target) Release/obj.target/validation/src/validation.o
  51.   SOLINK_MODULE(target) Release/obj.target/validation.node
  52.   COPY Release/validation.node
  53. make: 离开目录“/home/pengcx/AndroidStudioProjects/ReactNativeTest/node_modules /react-native/node_modules/ws/node_modules/utf-8-validate/build”
  54. > 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
  55. > node postinstall
  56. react@0.14.8 node_modules/react
  57. ├── 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)
  58. └── envify@3.4.0 (through@2.3.8, jstransform@10.1.0)
  59. react-native@0.25.1 node_modules/react-native
  60. ├── regenerator-runtime@0.9.5
  61. ├── react-clone-referenced-element@1.0.1
  62. ├── absolute-path@0.0.0
  63. ├── progress@1.1.8
  64. ├── stacktrace-parser@0.1.3
  65. ├── base64-js@0.0.8
  66. ├── graceful-fs@4.1.4
  67. ├── event-target-shim@1.1.1
  68. ├── wordwrap@1.0.0
  69. ├── react-timer-mixin@0.13.3
  70. ├── immutable@3.7.6
  71. ├── semver@5.1.0
  72. ├── image-size@0.3.5
  73. ├── opn@3.0.3 (object-assign@4.1.0)
  74. ├── bser@1.0.2 (node-int64@0.4.0)
  75. ├── json-stable-stringify@1.0.1 (jsonify@0.0.0)
  76. ├── Debug@2.2.0 (ms@0.7.1)
  77. ├── temp@0.8.3 (os-tmpdir@1.0.1, rimraf@2.2.8)
  78. ├── 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)
  79. ├── source-map@0.4.4 (amdefine@1.0.0)
  80. ├── mkdirp@0.5.1 (minimist@0.0.8)
  81. ├── rebound@0.0.13
  82. ├── optimist@0.6.1 (wordwrap@0.0.3, minimist@0.0.10)
  83. ├── worker-farm@1.3.1 (xtend@4.0.1, errno@0.1.4)
  84. ├── promise@7.1.1 (asap@2.0.3)
  85. ├── node-haste@2.9.6 (throat@2.0.2, denodeify@1.2.1)
  86. ├── 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)
  87. ├── 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)
  88. ├── node-fetch@1.5.2 (is-stream@1.1.0, encoding@0.1.12)
  89. ├── art@0.10.1
  90. ├── json5@0.4.0
  91. ├── uglify-js@2.6.2 (async@0.2.10, uglify-to-browserify@1.0.2, source-map@0.5.6, yargs@3.10.0)
  92. ├── 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)
  93. ├── 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)
  94. ├── 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)
  95. ├── babel-plugin-external-helpers@6.8.0 (babel-runtime@6.6.1)
  96. ├── 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)
  97. ├── babel-polyfill@6.8.0 (babel-regenerator-runtime@6.5.0, babel-runtime@6.6.1)
  98. ├── 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)
  99. ├── 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)
  100. ├── babylon@6.8.0 (babel-runtime@6.6.1)
  101. ├── lodash@3.10.1
  102. ├── joi@6.10.1 (topo@1.1.0, isemail@1.2.0, hoek@2.16.3, moment@2.13.0)
  103. ├── 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)
  104. ├── 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)
  105. ├── react-transform-hmr@1.0.4 (global@4.3.0, react-proxy@1.1.8)
  106. ├── 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)
  107. ├── core-js@2.4.0
  108. ├── 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)
  109. ├── ws@0.8.1 (options@0.0.6, ultron@1.0.2, bufferutil@1.2.1, utf-8-validate@1.2.1)
  110. └── 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)
  111. pengcx@pengcx-Ubuntu:~/AndroidStudioProjects/ReactNativeTest$ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
  112.   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
  113.                                  Dload  Upload   Total   Spent    Left  Speed
  114. 100  2654  100  2654    0     0   1522      0  0:00:01  0:00:01 –:–:–  1521

上面的代码会创建一个node模块,然后react-native作为npm依赖添加。现在打开新创建的package.json文件然后在scripts字段添加如下内容:

  1. “start”: “node node_modules/react-native/local-cli/cli.js start”

复制并粘贴下面这段代码到你的工程根目录下面的index.android.js—这是一个简单的React Native应用:

android.android.js文件
  1. ‘use strict’;
  2. var React = require(‘react’);
  3. var ReactNative = require(‘react-native’);
  4. var {
  5.   Text,
  6.   View,
  7.   StyleSheet,
  8.   AppRegistry
  9. } = ReactNative;
  10. class MyAwesomeApp extends React.Component {
  11.   render() {
  12.     return (
  13.       <View style={styles.container}>
  14.         <Text style={styles.hello}>Hello, World</Text>
  15.       </View>
  16.     )
  17.   }
  18. }
  19. var styles = StyleSheet.create({
  20.   container: {
  21.     flex: 1,
  22.     justifyContent: ‘center’,
  23.   },
  24.   hello: {
  25.     fontSize: 20,
  26.     textAlign: ‘center’,
  27.     margin: 10,
  28.   },
  29. });
  30. AppRegistry.registerComponent(‘MyAwesomeApp’, () => MyAwesomeApp);

五、运行你的应用

为了运行你的应用,首先要启动开发服务器。只需要在你的工程目录运行这段代码:
  1. pengcx@pengcx-Ubuntu:~/AndroidStudioProjects/ReactNativeTest$ npm start
  2.  ┌────────────────────────────────────────────────────────────────────────────┐
  3.  │  Running packager on port 8081.                                                                                                                       │
  4.  │                                                                                                                                                                           │
  5.  │  Keep this packager running while developing on any JS projects. Feel                                                                │
  6.  │  free to close this tab and run your own packager instance if you                                                                      │
  7.  │  prefer.                                                                                                                                                               │
  8.  │                                                                                                                                                                           │
  9.  │  https://github.com/facebook/react-native                                                                                                        │
  10.  │                                                                                                                                                                           │
  11.  └────────────────────────────────────────────────────────────────────────────┘
  12. Looking for JS files in
  13.    /home/pengcx/AndroidStudioProjects/ReactNativeTest
  14. [02:17:41] <START> Building Dependency Graph
  15. [02:17:57] <START> Crawling File System
  16. [Hot Module Replacement] Server listening on /hot
  17. 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”
        }
    }
}
分享到: 更多 (0)