├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── bin ├── commands │ ├── build.js │ ├── bundle.js │ ├── index.js │ ├── keygen.js │ ├── link.js │ ├── name.js │ └── version.js ├── ernc.js └── helper.js ├── images └── keygen.jpg ├── package.json └── usage ├── release-android-apk-cn.md └── release-android-apk-en.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.test.js 3 | 4 | node_modules/ 5 | .idea/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.test.js 3 | 4 | node_modules/ 5 | .idea/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # envirs-react-native-cli 2 | 3 | A react native command tool build by Envirs Team. 4 | 5 | ## Install 6 | 7 | ``` 8 | npm install envirs-react-native-cli -g 9 | ``` 10 | 11 | ## Commands 12 | 13 | > Note: Begin start any command, you should cd to your react-native project first. 14 | 15 | ### bundle 16 | 17 | Bundle the js files, support both ios and android. 18 | 19 | > *Options* 20 | > + -m --minify: whether to minify the bundle file. 21 | > + -d --dev: whether to use the dev mode. 22 | 23 | *example:* 24 | 25 | ``` 26 | cd ~/helloworld 27 | ernc bundle ios --minify 28 | ernc bundle android --minify 29 | ``` 30 | 31 | ### keygen 32 | 33 | Generate a private key for android apk. 34 | 35 | *example:* 36 | 37 | ``` 38 | cd ~/helloworld 39 | ernc keygen 40 | ``` 41 | 42 | *snapshot:* 43 | 44 | ![image](https://github.com/Spikef/envirs-react-native-cli/raw/master/images/keygen.jpg) 45 | 46 | ### build \ 47 | 48 | Build the app package. 49 | 50 | > *Platform* 51 | > + Android: build a android app. 52 | > + iOS: build a iOS app, not support yet. 53 | 54 | *example:* 55 | 56 | ``` 57 | cd ~/helloworld 58 | ernc build Android 59 | ``` 60 | 61 | ### name \ 62 | 63 | Set a new display name for app. 64 | 65 | ### name [Type] 66 | 67 | Set a new version for app. 68 | 69 | Type: 'code', 'name', 'all' or any allowed version value(eg 1, 1.0, 1.1.1), default is 'name'. 70 | 71 | When the type is a version value, the real type depends on the value format. 72 | 73 | *example:* 74 | 75 | ` 76 | 1 --> Type is 'code' 77 | 1.1 --> Type is 'name' 78 | 'name 1' --> Type is 'name' 79 | 'code 1.1' --> won't update 80 | ` 81 | 82 | > *Options* 83 | > + -p, --plus [n]: An integer to plus, default is 1. 84 | > + -m, --main: To update the main version number. 85 | > + -n, --minor: To update the minor version number. 86 | > + -f, --fix: To update the fix version number. 87 | 88 | ### link [Package] 89 | 90 | Use rnpm-plugin-link to link native packages to your app. More information to visit: (https://github.com/rnpm/rnpm) -------------------------------------------------------------------------------- /bin/commands/build.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | /*** 6 | * author: Spikef 7 | * mail: Spikef@foxmail.com 8 | * Copyright @ Envirs Team 9 | * http://envirs.com 10 | */ 11 | 12 | var fs = require('fs'); 13 | var path = require('path'); 14 | var child = require('child_process'); 15 | var helper = require('../helper'); 16 | var prompt = require('cli-prompt'); 17 | 18 | module.exports = function(Platform) { 19 | if ( !helper.isReactNativeProject() ) { 20 | console.log('It seems that you didn\'t run this inside a react-native project.'); 21 | return; 22 | } 23 | 24 | if (Platform.toLowerCase() == 'android') { 25 | var root = process.cwd(); 26 | var work = path.resolve(root, 'android'); 27 | var output = path.resolve(root, 'android/app/build/outputs/apk/app-release.apk'); 28 | var result = child.spawnSync('./gradlew', ['assembleRelease'], {stdio: 'inherit', cwd: work}); 29 | if (result.status == 0) { 30 | // success 31 | console.log('Successfully build the apk, you can find the file here:'); 32 | console.log(output); 33 | 34 | prompt.multi( 35 | [{ 36 | label: 'Would you like to open the folder right now?', 37 | key: 'open', type: 'boolean', default: 'true' 38 | }], 39 | function(options){ 40 | if (options.open) { 41 | child.exec('open ' + path.dirname(output)); 42 | } 43 | } 44 | ); 45 | } 46 | } else { 47 | console.log('Only support build android yet.'); 48 | } 49 | }; -------------------------------------------------------------------------------- /bin/commands/bundle.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | /*** 6 | * author: Spikef 7 | * mail: Spikef@foxmail.com 8 | * Copyright @ Envirs Team 9 | * http://envirs.com 10 | */ 11 | 12 | var fs = require('fs'); 13 | var path = require('path'); 14 | var child = require('child_process'); 15 | var helper = require('../helper'); 16 | var prompt = require('cli-prompt'); 17 | 18 | module.exports = function(Platform, options) { 19 | if ( !helper.isReactNativeProject() ) { 20 | console.log('It seems that you didn\'t run this inside a react-native project.'); 21 | return; 22 | } else { 23 | console.log('Begin to save the js bundle, please wait a seconds.'); 24 | } 25 | 26 | var minify = options.minify ? true : false; 27 | var develop = options.dev ? true : false; 28 | 29 | if (Platform.toLowerCase() == 'android') { 30 | let root = process.cwd(); 31 | let main = helper.getAndroidPackage(path.resolve(root, 'android/app/src/main/AndroidManifest.xml')); 32 | let output = path.resolve(root, helper.bundleLocal.android, helper.getBundleAsset(main)); 33 | let assets = path.resolve(output, '../'); 34 | 35 | if (!fs.existsSync(assets)) { 36 | fs.mkdirSync(assets) 37 | } 38 | 39 | let args = [ 40 | 'bundle', '--platform', 'android', '--entry-file', 'index.android.js', 41 | '--bundle-output', output, 42 | '--assets-dest', 'android/app/src/main/res/', 43 | '--reset-cache', 'true' 44 | ]; 45 | 46 | args.push('--minify', minify); 47 | args.push('--dev', develop); 48 | 49 | let result = child.spawnSync('react-native', args, {stdio: 'inherit', cwd: root}); 50 | 51 | if (result.status == 0) { 52 | // success 53 | console.log('Successfully save the js bundle, you can find the file here:'); 54 | console.log(output); 55 | 56 | prompt.multi( 57 | [{ 58 | label: 'Would you like to open the folder right now?', 59 | key: 'open', type: 'boolean', default: 'false' 60 | }], 61 | function(options){ 62 | if (options.open) { 63 | child.exec('open ' + path.dirname(output)); 64 | } 65 | } 66 | ); 67 | } 68 | } else { 69 | let root = process.cwd(); 70 | let output = path.resolve(root, helper.bundleLocal.iOS); 71 | 72 | let args = [ 73 | 'bundle', '--platform', 'ios', '--entry-file', 'index.ios.js', 74 | '--bundle-output', output, 75 | '--reset-cache', 'true' 76 | ]; 77 | 78 | args.push('--minify', minify); 79 | args.push('--dev', develop); 80 | 81 | let result = child.spawnSync('react-native', args, {stdio: 'inherit', cwd: root}); 82 | 83 | if (result.status == 0) { 84 | // success 85 | console.log('Successfully save the js bundle, you can find the file here:'); 86 | console.log(output); 87 | 88 | prompt.multi( 89 | [{ 90 | label: 'Would you like to open the folder right now?', 91 | key: 'open', type: 'boolean', default: 'false' 92 | }], 93 | function(options){ 94 | if (options.open) { 95 | child.exec('open ' + path.dirname(output)); 96 | } 97 | } 98 | ); 99 | } 100 | } 101 | }; -------------------------------------------------------------------------------- /bin/commands/index.js: -------------------------------------------------------------------------------- 1 | /*** 2 | * author: Spikef 3 | * mail: Spikef@foxmail.com 4 | * Copyright @ Envirs Team 5 | * http://envirs.com 6 | */ 7 | 8 | exports.keygen = require('./keygen'); 9 | exports.bundle = require('./bundle'); 10 | exports.build = require('./build'); 11 | exports.name = require('./name'); 12 | exports.version = require('./version'); 13 | 14 | exports.link = require('./link'); -------------------------------------------------------------------------------- /bin/commands/keygen.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | /*** 6 | * author: Spikef 7 | * mail: Spikef@foxmail.com 8 | * Copyright @ Envirs Team 9 | * http://envirs.com 10 | */ 11 | 12 | var fs = require('fs'); 13 | var path = require('path'); 14 | var child = require('child_process'); 15 | var helper = require('../helper'); 16 | var prompt = require('cli-prompt'); 17 | 18 | module.exports = function() { 19 | if ( !helper.isReactNativeProject() ) { 20 | console.log('It seems that you didn\'t run this inside a react-native project.'); 21 | return; 22 | } 23 | 24 | // prompt user input key args 25 | prompt.multi([ 26 | { 27 | label: 'Input the name of the key (such as: mykey)', 28 | key: 'keyName', 29 | default: '', 30 | validate: function (val) { 31 | if (val.length < 1) { 32 | throw new Error ('key name must be at least 1 characters'); 33 | } 34 | } 35 | }, 36 | { 37 | label: 'Input the alias name of the key (such as: reactnative)', 38 | key: 'keyAlias', 39 | default: '', 40 | validate: function (val) { 41 | if (val.length < 1) { 42 | throw new Error ('key alias name must be at least 1 characters'); 43 | } 44 | } 45 | }, 46 | { 47 | label: 'Input the file name of the key (such as: release-key)', 48 | key: 'keyFile', 49 | validate: function (val) { 50 | if (val.length < 1){ 51 | throw new Error('key file name must be at least 1 characters') 52 | } 53 | } 54 | }, 55 | { 56 | label: 'Input the password of the key (at least 6 characters)', 57 | key: 'password', 58 | type: 'password', 59 | validate: function (val) { 60 | if (val.length < 6){ 61 | throw new Error('password must be at least 6 characters') 62 | } 63 | } 64 | } 65 | ], function(options){ 66 | var keyAlias = options.keyAlias; 67 | var keyName = options.keyName; 68 | var keyFile = options.keyFile; 69 | var password = options.password; 70 | 71 | var root = process.cwd(); 72 | var keyPath = path.resolve(root, 'android/app/' + keyFile + '.keystore'); 73 | 74 | if ( fs.existsSync(keyPath) ) fs.unlinkSync(keyPath); 75 | 76 | var args = [ 77 | '-genkey', '-v', '-keyalg', 'RSA', '-validity', '20000', 78 | '-keystore', keyName +'.keystore', 79 | '-alias', keyAlias, 80 | '-keystore', keyPath, 81 | '-keypass', password, 82 | '-storepass', password 83 | ]; 84 | 85 | var result = child.spawnSync('keytool', args, {stdio: 'inherit'}); 86 | if (result.status == 0) { 87 | // success 88 | helper.setBuildGradle( 89 | path.resolve(root, 'android/app/build.gradle'), 90 | {keyAlias: keyAlias, keyFile: keyFile, keyName: keyName, password: password} 91 | ); 92 | 93 | console.log('Successfully generated your key, now try [ernc build Android] to release the apk.'); 94 | } 95 | }); 96 | }; -------------------------------------------------------------------------------- /bin/commands/link.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | /** 6 | * Usage: link native packages for app 7 | * Author: Spikef < Spikef@Foxmail.com > 8 | * Copyright: Envirs Team < http://envirs.com > 9 | */ 10 | 11 | var link = require('rnpm-plugin-link'); 12 | 13 | module.exports = function(name) { 14 | var config = require('rnpm/src/config'); 15 | 16 | return link.func(config, [name]); 17 | }; -------------------------------------------------------------------------------- /bin/commands/name.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | /** 6 | * Usage: Set the display name for app 7 | * Author: Spikef < Spikef@Foxmail.com > 8 | * Copyright: Envirs Team < http://envirs.com > 9 | */ 10 | 11 | var fs = require('fs'); 12 | var path = require('path'); 13 | var helper = require('../helper'); 14 | var prompt = require('cli-prompt'); 15 | 16 | module.exports = function(name) { 17 | if ( !helper.isReactNativeProject() ) { 18 | console.log('It seems that you didn\'t run this inside a react-native project.'); 19 | return; 20 | } 21 | 22 | var root = process.cwd(); 23 | var project = helper.getProjectName(); 24 | 25 | // iOS: Info.plist 26 | var info = path.resolve(root, 'ios/' + project + '/Info.plist'); 27 | var key = 'CFBundleDisplayName'; 28 | var ios = fs.readFileSync(info, 'utf8'); 29 | 30 | if ( ios.indexOf(key) > -1 ) { 31 | ios = ios.replace(/(CFBundleDisplayName<\/key>\s*)([^<]*)(<\/string>)/, '$1' + name + '$3'); 32 | } else { 33 | ios = ios.replace(/\t\n/, 'CFBundleDisplayName\n\t' + name + '\n\t'); 34 | } 35 | 36 | fs.writeFileSync(info, ios); 37 | 38 | // Android: strings.xml 39 | var strings = path.resolve(root, 'android/app/src/main/res/values/strings.xml'); 40 | var android = fs.readFileSync(strings, 'utf8'); 41 | android = android.replace(/()([^<]*)(<\/string>)/, '$1' + name + '$3'); 42 | 43 | fs.writeFileSync(strings, android); 44 | 45 | console.log('Successfully set the display name to: ' + name); 46 | }; -------------------------------------------------------------------------------- /bin/commands/version.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | /** 6 | * Usage: update the version name(bundle version short) or version code(bundle version) 7 | * Author: Spikef < Spikef@Foxmail.com > 8 | * Copyright: Envirs Team < http://envirs.com > 9 | */ 10 | 11 | var fs = require('fs'); 12 | var path = require('path'); 13 | var helper = require('../helper'); 14 | var prompt = require('cli-prompt'); 15 | 16 | module.exports = function(Type, options) { 17 | if ( !helper.isReactNativeProject() ) { 18 | console.log('It seems that you didn\'t run this inside a react-native project.'); 19 | return; 20 | } 21 | 22 | var root = process.cwd(); 23 | var project = helper.getProjectName(); 24 | 25 | var version = {ios: {}, android: {}}; 26 | 27 | // iOS: Info.plist 28 | var info = path.resolve(root, 'ios/' + project + '/Info.plist'); 29 | var ios = fs.readFileSync(info, 'utf8'); 30 | 31 | version.ios.name = ios.match(/(CFBundleShortVersionString<\/key>\s*)([^<]*)(<\/string>)/)[2]; 32 | version.ios.code = ios.match(/(CFBundleVersion<\/key>\s*)([^<]*)(<\/string>)/)[2]; 33 | 34 | parse(Type, options, version.ios); 35 | 36 | ios = ios.replace(/(CFBundleShortVersionString<\/key>\s*)([^<]*)(<\/string>)/, '$1' + version.ios.name + '$3'); 37 | ios = ios.replace(/(CFBundleVersion<\/key>\s*)([^<]*)(<\/string>)/, '$1' + version.ios.code + '$3'); 38 | 39 | fs.writeFileSync(info, ios); 40 | 41 | // Android: build.gradle 42 | var build = path.resolve(root, 'android/app/build.gradle'); 43 | var android = fs.readFileSync(build, 'utf8'); 44 | 45 | version.android.name = android.match(/(versionName\s+")([\d\.]+)(")/)[2]; 46 | version.android.code = android.match(/(versionCode\s+)([\d]+)/)[2]; 47 | 48 | parse(Type, options, version.android); 49 | 50 | android = android.replace(/(versionName\s+")([\d\.]+)(")/, '$1' + version.android.name + '$3'); 51 | android = android.replace(/(versionCode\s+)([\d]+)/, '$1' + version.android.code); 52 | 53 | fs.writeFileSync(build, android); 54 | 55 | console.log('Successfully set the version to: \n' + JSON.format(version.ios)); 56 | }; 57 | 58 | function parse(type, args, vers) { 59 | var isVal, isMain, isMinor, isFix, name, code, step; 60 | 61 | isVal = /^(name )?(\d+)(\.\d+)?(\.\d+)?$/.test(type); 62 | isMain = args.main ? true : false; 63 | isFix = args.fix ? true : false; 64 | isMinor = args.minor || (!isMain && !isFix) ? true : false; 65 | 66 | if ( isVal ) { 67 | if ( type.indexOf('name ') === 0 || type.indexOf('.') > 0 ) { 68 | name = type.replace('name ', ''); 69 | type = 'name'; 70 | } else { 71 | code = type; 72 | type = 'code'; 73 | } 74 | } else { 75 | step = Number(args.plus) || 1; 76 | code = parseInt(vers.code) + step; 77 | name = vers.name; 78 | 79 | name = name.replace(/^(\d+)(\.\d+)?(\.\d+)?$/, function($0, $1, $2, $3) { 80 | if ( isMain ) { 81 | $1 = Number($1) || 0; 82 | $1 = $1 + step; 83 | $1 = String($1); 84 | } 85 | 86 | if ( isMinor ) { 87 | $2 = Number($2) || 0; 88 | $2 = $2 + step; 89 | $2 = '.' + String($2); 90 | } 91 | 92 | if ( isFix ) { 93 | $3 = Number($3) || 0; 94 | $3 = $3 + step; 95 | $3 = '.' + String($3); 96 | } 97 | 98 | return ($1 || '') + ($2 || '') + ($3 || ''); 99 | }); 100 | } 101 | 102 | if ( type === 'name' || type === 'all' || !type && name ) { 103 | vers.name = name; 104 | } 105 | 106 | if ( type === 'code' || type === 'all' && code && /^\d+$/.test(code) ) { 107 | vers.code = code; 108 | } 109 | } -------------------------------------------------------------------------------- /bin/ernc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | /*** 6 | * author: Spikef 7 | * mail: Spikef@foxmail.com 8 | * Copyright @ Envirs Team 9 | * http://envirs.com 10 | */ 11 | 12 | var Package = require('../package.json'); 13 | var Command = require('./commands'); 14 | var program = require('commander'); 15 | var prompt = require('cli-prompt'); 16 | 17 | program 18 | .version(Package.version, '-v, --version'); 19 | 20 | program 21 | .command('keygen') 22 | .description('generate an android keystore') 23 | .action(Command.keygen); 24 | 25 | program 26 | .command('bundle ') 27 | .description('bundle the android files') 28 | .option('-m, --minify', 'whether to minify the bundle file') 29 | .option('-d, --dev', 'whether to minify the bundle file') 30 | .action(Command.bundle); 31 | 32 | program 33 | .command('build ') 34 | .description('build the app package') 35 | .action(Command.build); 36 | 37 | program 38 | .command('name ') 39 | .description('set the display name for app') 40 | .action(Command.name); 41 | 42 | program 43 | .command('versions [Type]') 44 | .description('update the version name(bundle version short) or version code(bundle version)') 45 | .option('-p, --plus [n]', 'An integer to plus') 46 | .option('-m, --main', 'To update the main version number') 47 | .option('-n, --minor', 'To update the minor version number') 48 | .option('-f, --fix', 'To update the fix version number') 49 | .action(Command.version); 50 | 51 | program 52 | .command('link [PackageName]') 53 | .description('Updates your project and links all native dependencies') 54 | .action(Command.link); 55 | 56 | program.parse(process.argv); -------------------------------------------------------------------------------- /bin/helper.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | /*** 6 | * author: Spikef 7 | * mail: Spikef@foxmail.com 8 | * Copyright @ Envirs Team 9 | * http://envirs.com 10 | */ 11 | 12 | // 检测是否ReactNative项目目录 13 | exports.isReactNativeProject = function() { 14 | var fs = require('fs'); 15 | var path = require('path'); 16 | 17 | var dpath = process.cwd(); //获取当前运行目录 18 | var pfile = path.resolve(dpath, 'package.json'); 19 | 20 | if ( fs.existsSync(pfile) ) { 21 | var pack = require(pfile); 22 | return !!pack['dependencies']['react-native']; 23 | } else { 24 | return false; 25 | } 26 | }; 27 | 28 | // 获取AndroidManifest.xml中java主程序包的包名 29 | exports.getAndroidPackage = function(xml) { 30 | var fs = require('fs'); 31 | var path = require('path'); 32 | var value = '', name = ''; 33 | 34 | if (fs.existsSync(xml)) { 35 | var content = fs.readFileSync(xml, 'utf8'); 36 | if (content) { 37 | var matches = content.match(/android:name="\.([^"]+)"/); 38 | if (matches) name = matches[1]; 39 | } 40 | } 41 | 42 | var dir = path.resolve(path.dirname(xml), 'java'); 43 | var files = this.getFiles(dir); 44 | 45 | for (let i=0; i= 4.0.0" 37 | }, 38 | "license": "MIT" 39 | } 40 | -------------------------------------------------------------------------------- /usage/release-android-apk-cn.md: -------------------------------------------------------------------------------- 1 | # 生成真机上运行的APK文件 (Mac Tested Only) 2 | 3 | 当你的React Android程序已经运行起来之后,可以通过以下步骤打包生成可以在真机上安装并运行的APK文件。 4 | 5 | ## 第一步:保存JS包到本地 6 | 该步的目的是把React Native的JS包保存到应用目录下,以使该APP能够脱离开发环境独立运行。 7 | 8 | > 1. 安装envirs-react-native-cli 9 | > 2. 打开终端 10 | > 3. cd *<你的项目目录>* 11 | > 4. 在终端执行 *ernc bundle --minify* 12 | 13 | 该命令会自动帮助你把你的JS包以正确的名称保存到正确的位置,并压缩JS包文件。 14 | 15 | ## 第二步:生成签名 16 | Android应用必须经过签名才能在未root的真机上安装,该步骤将指引你生成一个自己的签名。 17 | 18 | > 1. 在终端执行 *ernc keygen* 19 | > 2. 按照指引输入生成密钥所必需的信息 20 | 21 | 该命令会引导你生成签名文件,并保存到APP项目目录下,同时增加build.gradle文件中密钥的设置。 22 | 23 | ## 第三步: 打包应用 24 | > 1. 在终端执行 *ernc build Android* 25 | 26 | ## 参考 27 | 28 | 安装Android运行环境:http://reactnative.cn/docs/android-setup.html#content 29 | React Native Android的配置说明:https://github.com/ggchxx/React-Native-Android-Config 30 | Mac Android签名生成keystore:http://www.cnblogs.com/liqw/p/4064662.html 31 | ernc帮助文档:https://github.com/Spikef/envirs-react-native-cli/blob/master/README.md -------------------------------------------------------------------------------- /usage/release-android-apk-en.md: -------------------------------------------------------------------------------- 1 | # Release a apk file (Mac Tested Only) 2 | 3 | You can use the follow steps to release a apk file to install on your device easily. 4 | 5 | ## Step 1:Save the JS bundle to local 6 | 7 | > 1. npm install envirs-react-native-cli -g 8 | > 2. Open the terminal 9 | > 3. cd *\* 10 | > 4. ernc bundle android --minify 11 | 12 | ## Step 3:Generate a key file 13 | The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device. 14 | 15 | > 1. ernc keygen 16 | > 2. input the information needed step by step 17 | 18 | ## Step 4: build the apk 19 | > 1. ernc build Android 20 | 21 | ## Reference 22 | 23 | Android Setup:https://facebook.github.io/react-native/docs/android-setup.html#content 24 | React Native Android Config:https://github.com/ggchxx/React-Native-Android-Config 25 | Signing Your App Manually:http://developer.android.com/intl/zh-cn/tools/publishing/app-signing.html#signing-manually 26 | ernc document:https://github.com/Spikef/envirs-react-native-cli/blob/master/README.md --------------------------------------------------------------------------------