由于React并没有假设你其余部分的技术栈—它通常只作为MVC模型中的V存在—它也很容易嵌入到一个并非由React Native开发的应用中。
一、需求
1.一个已有的、基于gradle构建的Android应用;
2.Node.js;
二、准备你的App
compile 'com.facebook.react:react-native:0.20.+'2.在你的AndroidManifest.xml里,增加Internet访问权限;
这个仅仅在调试模式从服务器加载JavaScript代码的时候用到,你可以在构建发行包的时候把这条去掉;
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代码。
在你的工程根目录,运行以下代码:
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,minimatch@2.0.10,babel-generator@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,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,yeoman-welcome@1.0.1,async@1.5.2,mime@1.3.4,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,run-async@0.1.0,shelljs@0.5.3,yeoman-assert@2.2.1,cli-table@0.3.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.六、应用程序运行如下:
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版本,引用项目根目录下的最新版本:
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.facebook.react:react-native:+'
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"
}
}
}