Coder Social home page Coder Social logo

react-native-start's People

Contributors

codingecho avatar

Watchers

 avatar  avatar

Forkers

wujing0107

react-native-start's Issues

React Native 知识快速预览

React-Native 需要掌握的知识

不包含IOS、Android原生开发的知识

1 JSX

**定义:**类XML的JavaScript语法扩展

var Avatar = React.createClass({
    render: function() {
        return (
        <div>
            <ProfilePic filename={this.props.filename} />
            <ProfileLink {...this.props} />
        </div>
        );
}
});

var ProfilePic = React.createClass({
    render: function() {
        return (
        <img src={'http://s.amazeui.org/media/i/demos/' + this.props.filename} />
    );
}
});

var ProfileLink = React.createClass({
    render: function() {
        return (
        <a href={'http://s.amazeui.org/media/i/demos/' + this.props.filename}>
            {this.props.filedesc}
        </a>
    );
  }
});

ReactDOM.render(
<Avatar filename="bing-2.jpg" filedesc="晚霞" />,
document.getElementById('demo'));

ReactDOM.render(
<Avatar filename="bing-3.jpg" filedesc="里约内热卢" />,
document.getElementById('demo2'));

2 ES6(ES2015)

这里不列举所有的ES6新特性,只选择常用的进行描述。

2.1 let 和 const

let

ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

{
  let a = 10;
  var b = 1;
}

console.log(a); // ReferenceError: a is not defined.
console.log(b); // 1

const

const 声明一个只读的常量。一旦声明,常量的值就不能改变。

'use strict';
const PI = 3.1415;
console.log(PI); // 3.1415
// 尝试赋值
PI = 3; // TypeError: "PI" is read-only

2.2 变量的解构赋值

reqire('react-native'); // 老的写法(类似reqire.js)
import ReactNative from 'react-native'; // 作用类似于Java中的import

var {
    StyleSheet,
    View,
    Text,
    AppRegistry,
    Image,
  } = ReactNative;

/* 等价于 */

var StyleSheet = ReactNative.StyleSheet;
var View = ReactNative.View;
var Text = ReactNative.Text;
var AppRegistry = ReactNative.AppRegistry;
var Image = ReactNative.Image;

2.3 Promise

Promise是异步编程的一种解决方案,是传统的解决方案(回调函数和事件)的替代方案

var Util = {
    //post请求
    post: function (url, data, callback) {
        var fetchOptions = {
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)
        };
        // fetch 返回一个Promise对象
        fetch(url, fetchOptions)
        .then((response) => response.text())
        .then((responseText) => {
            callback(JSON.parse(responseText));
    });
}
};

2.4 class

ES5之前

function Point(x,y){
    this.x = x;
    this.y = y;
}

Point.prototype.toString = function () {
    return '(' + this.x + ', ' + this.y + ')';
}    

ES6

//定义类
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    // 静态方法,调用方式:Point.classMethod();
    static classMethod() {
        return 'hello';
    }
    // 静态属性
    static z:0

    toString() {
        return '(' + this.x + ', ' + this.y + ')';
    }
}

继承

class ColorPoint extends Point {
    constructor(x, y, color) {
      super(x, y); // 调用父类的constructor(x, y)
        this.color = color;
    }

    toString() {
        return this.color + ' ' + super.toString(); // 调用父类的toString()
    }
}

2.5 module

ES6的class只是面向对象编程的语法糖,升级了ES5的构造函数的原型链继承的写法,
并没有解决模块化问题。module功能就是为了解决这个问题而提出的。

    // CommonJS模块
    let { stat, exists, readFile } = require('fs');

    // 等同于
    let _fs = require('fs');
    let stat = _fs.stat, exists = _fs.exists, readfile = _fs.readfile;

    // ES6模块
    import { stat, exists, readFile } from 'fs';

2.5.1 export

导出变量

// 写法一
export var m = 1;

// 写法二
var m = 1;
export {m};

// 写法三
var n = 1;
export {n as m};

导出function和class

// 报错
function f() {}
export f;

// 正确
export function f() {};

// 正确
function f() {}
export {f};

2.5.2 import

// person.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};
// main.js

import {firstName, lastName, year} from './person'; // 不用加扩展名“.js”

function setName(element) {
    element.textContent = firstName + ' ' + lastName;
}

2.5.3 default export

export default命令,为模块指定默认输出。

    // export-default.js
    export default function () {
        console.log('foo');
    }
    /*
    上面代码是一个模块文件export-default.js,它的默认输出是一个函数。

    其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
    */
    // import-default.js
    import customName from './export-default'; 
    customName(); // 'foo'

2.6 扩展运算符(...)和箭头函数(Lambda表达式)

扩展运算符可以将一个数组转为用逗号分隔的参数序列。

function add(x, y) {
  return x + y;
}

var numbers = [4, 38];
add(...numbers) // 42

JSX 中的延展属性

  var props = {};
  props.foo = 'x';
  props.bar = 'y';
  var component = <Component {...props} />;
  // 等价于
  var component = <Component foo='x' bar='y' />;

ES6允许使用“箭头”(=>)定义函数

var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

node.js 命令

npm的全称是Node Package Manager,是一个NodeJS包管理和分发工具。类似的
有cnpm(淘宝的npm),rnpm(React npm),anpm(Atom npm)

npm install express            # 本地安装
npm install express -g         # 全局安装
npm install express --save     # 安装并添加到依赖(package.json)
npm i express   # 简写 npm install express

jQuery 编程最佳实践

jQuery 编程最佳实践


1 Writing Better jQuery Code

1.1 用变量缓存jQuery对象

DOM遍历是昂贵的,所以用变量来缓存需要复用的对象。

// bad
if ($('#userName').length) {
    var userName = $('#username');
    // ...
    $('#username').val();
}

// good
var $userName = $('#userName');
if ($userName.length) {
    var userName = $userName.val();
    // ...
    $userName.val(userName);
}

区分普通JavaScript变量和jQuery变量,变量前加美元符$,如上面示例中的:$userName

!!!更好的做法!!!
并不是所有的元素都有val()方法,有时候需要text()方法,所以
HTML这样写:

<input type="text" id="txtUserName" name="userName" />

JavaScript就可以写为:

var $txtUserName = $('txtUserName'),
    userName = $txtUserName.val();

1.2 避免意外的全局变量

// bad
$userName = $('#userName');
if ($userName.length) {
    var userName = $userName.val();
    // ...
    $userName.val(userName);
}

// good
var $userName = $('#userName');

1.3 使用使用$前缀区分jQuery对象和普通变量

// bad
var first = $('#first'); 
var second = $('#second'); 

// better - we use to put $ symbol before jQuery-manipulated objects
var $first = $('#first');
var $second = $('#second');
var value = $first.val(); 

1.4 单var模式

var $first = $('#first'),
    $second = $('#second'),
    value = $first.val(),
    k = 3,
    cookiestring = 'SOMECOOKIESPLEASE',
    myArray = {},
    i,
    j;

1.5 优先使用on来绑定事件

// bad
$first.click(function () {
    $first.css('border', '1px solid red');
    $first.css('color', 'blue');
});

$first.hover(function () {
    $first.css('border', '1px solid red');
});

// better(比上面的写法要好点)
$first.on('click', function () {
    $first.css('border', '1px solid red');
    $first.css('color', 'blue');
});

$first.on('hover', function () {
    $first.css('border', '1px solid red');
});

// good
function changeStyle() {
    // 这样的写法同样不好
    $first.css('border', '1px solid red');
    $first.css('color', 'blue');
    /*
     * // 更好的写法,定义一个CSS样式,比如:.checked
     * $first.css('checked');
     */
}

function tiggerHoverStyle() {
    $first.css('border', '1px solid red');
}

$first.on('click', changeStyle)
      .on('hover', tiggerHoverStyle);

1.6 使用jQuery链式写法

// bad
$second.html(value);
$second.on('click', function () { alert('hello everybody'); });
$second.fadeIn('slow');
$second.animate({ height: '120px' }, 500);

// good
$second.html(value);
$second.on('click', function () {alert('hello everybody');}).fadeIn('slow').animate({ height: '120px' }, 500);

1.7 让你的代码具有可读性

// bad
$second.html(value);
$second.on('click', function () { alert('hello everybody'); }).fadeIn('slow').animate({ height: '120px' }, 500);

// good
$second.html(value);
$second.on('click', function () {
 alert('hello everybody'); })
       .fadeIn('slow')
       .animate({ height: '120px' }, 500);

1.8 使用短路求值

// bad
function initVar($myVar) {
    if (!$myVar) {
        $myVar = $('#selector');
    }
}

// good
function initVar($myVar) {
    $myVar = $myVar || $('#selector');
}

// good 
function getValue($myVar) {
    var val;
    $myVar = $myVar || $('#selector');
    val = $myVar && $myVar.val();
}

1.9 简写表达式

// bad
if (collection.length > 0) {
    //..
}

// better
if (collection.length) {
    //..
}

1.10 Detach Elements When Doing Heavy Manipulations

// bad    
var $container = $('#container'),
    $containerLi = $('#container li'),
    $element = null;
$element = $containerLi.first();
// ... a lot of complicated things

// better
var $container = $('#container'),
    $containerLi = $container.find('li'),
    $element = null;
$element = $containerLi.first().detach();
// ...a lot of complicated things                               
$container.append($element);

1.11 你应该知道jQuery技巧

// bad
$('#id').data(key, value);

// better (faster)
$.data('#id', key, value);

1.11.1 Use Subqueries Caching Parents

// bad
var $container = $('#container'),
    $containerLi = $('#container li'),
    $containerLiSpan = $('#container li span');

// better (faster)
var $container = $('#container'),
    $containerLi = $container.find('li'),
    $containerLiSpan = $containerLi.find('span');

1.11.2 Avoid Universal Selectors(避免通用选择器)

// bad                                                         
$('.container > *');

// better                                                      
$('.container').children();

1.11.3 Avoid Implied Universal Selectors(避免隐式通用选择器)

When you leave off the selector, the universal selector (*) is still implied.

// bad     
$('.someclass :radio');

// better                                                     
$('.someclass input:radio');

1.11.4 优化选择器

别画蛇添足,耗时且代码不美观。

// bad 
$('div#myid');                                                
$('div#footer a.myLink');

// better
$('#myid');
$('#footer .myLink');
// bad
$('#outer #inner'); 

// better
$('#inner'); 

1.12 尝试使用最新版本的jQuery库

(不要使用已经过时的方法)

// bad - live is deprecated
$('#stuff').live('click', function () {
    console.log('hooray');
});

// better
$('#stuff').on('click', function () {
    console.log('hooray');
});

2 最佳实践

2.1 加载jQuery

(1)坚持使用CDN来加载jQuery,这种别人服务器免费帮你托管文件的便宜干嘛不占呢

<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery-2.1.4.min.js" type="text/javascript"><\/script>')</script>

(2)安全起见,最好还是提供一个本地备份以便在无法从远程CDN服务器获取jQuery时网站也能工作,如上面代码所示。详情见此。

(3)使用裸协议的URL(也就是说去掉http:或者https:),如上面代码展示的那样。

(4)如果可能,尽量将你的JavaScriptjQuery代码放到页面底部。详情移步这里。

(5)该使用哪个版本?

如果你想兼容IE678请不要用2.x的版本针对极少数不用考虑兼容性的幸运儿,极力推荐使用最新版本的jQuery当从CDN服务器加载jQuery时,最好把版本写全(比如1.11.0而不是1.11或者直接写个1)千万莫重复加载

(6)如果你同时还使用了其他JS框架诸如Prototype, MooTools, Zepto云云,因为他们也使用了$符号,所以你就不要再用美刀符号来进行jQuery 编码了,而请用'jQuery'代替。并且调用$.noConflict()保证不会有冲突出现。

(7)要检测浏览器对一些新特性是否支持,请用Modernizr

2.2 关于变量

(1)jQuery类型的变量最好加个$前缀。

(2)时常将jQuery选择器返回的内容存进变量以便重用

var $products = $('div.products'); // 慢
var $products = $('.products'); // 快

(3)使用驼峰命名

var orderList;

2.3 关于选择器

(1)尽量ID选择器。其背后机理其实是调用原生的document.getElementById(),所以速度较其他选择器快。

(2)使用类选择器时不要指定元素的类型。

var $products = $('div.products'); // 慢
var $products = $('.products'); // 快

(3)ID父亲容器下面再查找子元素请用.find()方法。这样做快的原因是通过id选择元素不会使用Sizzle引擎。详情看这里

(4)多级查找中,右边尽量指定得详细点而左边则尽量简单点。

// 丑陋
$('div.data .gonzalez');

// 优化后
$('.data td.gonzalez');

(5)避免冗余。详情或者查看性能比较

$('.data table.attendees td.gonzalez');

// 好的方式:去掉了中间的冗余
$('.data td.gonzalez');

(6)指定选择的上下文。

// 劣质的代码:因为需要遍历整个DOM来找到.class
$('.class');

// 高品代码:因为只需在指定容器范围内进行查找
$('.class', '#class-container');

(7)不要使用万能选择器。查看具体阐释

$('div.container > *'); // 差
$('div.container').children(); // 棒

8.警惕隐式的万能选择器。省略的情况下其实使用的就是*号通配符。

$('div.someclass :radio'); // 差
$('div.someclass input:radio'); // 棒

9.ID已经表示唯一了,背后使用的是document.getElementById(),所以不要跟其他选择器混搭了。

$('#outer #inner'); // 脏
$('div#inner'); // 乱
$('.outer-container #inner'); // 差
$('#inner'); // 干净利落,后台只需调用document.getElementById()

2.4 DOM操作相关

(1)操作任何元素前先将其从文档卸载,完了再贴回去。

var $myList = $("#list-container > ul").detach();
//...一大堆对$myList的处理
$myList.appendTo("#list-container");

(2)代码里将HTML组织好后再一次性贴到DOM中去。具体来说,性能比较

// 这样不好
var $myList = $("#list");
for (var i = 0; i < 10000; i++) {
    $myList.append("<li>" + i + "</li>");
}

// 这样好
var $myList = $("#list");
var list = "";
for (var i = 0; i < 10000; i++) {
    list += "<li>" + i + "</li>";
}
$myList.html(list);

// 但这样更好var array = []; 
for (var i = 0; i < 10000; i++) {
    array[i] = "<li>" + i + "</li>";
}
$myList.html(array.join(''));

(3)不要处理不存在的元素。

// 无良的做法:jQuery后台要跑完三个函数后才会知道这个元素其实根本不存在
$("#nosuchthing").slideUp();
// 应该这样
var $mySelection = $("#nosuchthing");
if ($mySelection.length) {
    $mySelection.slideUp();
}

2.5事件相关

(1)一个页面只写一个文档ready事件的处理程序。这样代码既清晰好调试,又容易跟踪代码的进程。

(2)不要用匿名函数来做事件的回调。匿名函数不易调试维护测试和复用。或许你想较真,看看这里吧

// 不要这样
$("#myLink").on("click", function(){
    //...
});

// 这样
function myLinkClickHandler() {
 //...
}

$("#myLink").on("click", myLinkClickHandler);

3.处理文档ready事件的回调也不要用匿名函数,匿名函数不易调试维护测试和复用

$(function () {
    // ... 
}); // 糟糕的做法:无法利用此函数也无法为其写测试用例

// 好的做法
$(initPage);
// 或 $(document).ready(initPage);
function initPage() {
    // 这里你可以进行程序的初始化了
}

// 自己的写法
(function ($) {

    var MyApp = {};
    MyApp.init = function () {
        console.log('初始化工作');
    };

    $(MyApp.init);

}(jQuery));

(4)进一步,最好也将ready事件的处理程序放到外部文件中引入到页面,而页面中内嵌的代码只需调用即可。

<script src="my-document-ready.js"></script>
<script>
// 初始化一些必要的全局变量
    $(document).ready(initPage); // 或 $(initPage);
</script>

(5)千万不要写内联到HTML的JS代码,这是调试的梦魇!应该总是用jQuery来绑定事件自带程序,这样也方便随时动态地取消绑定。

<a id="myLink" href="#" onclick="myEventHandler();">my link</a> <!--不好 -->
$("#myLink").on("click", myEventHandler); // GOOD

6.如果可能尽量在绑定事件处理程序时使用一个命名空间,这样可以方便地取消绑定而不会影响其他绑定。

$("#myLink").on("click.mySpecialClick", myEventHandler); // 不错
// 之后,让我们优雅地解除绑定
$("#myLink").unbind("click.mySpecialClick");

2.6 异步操作

(1) 直接用$.ajax()而不要去用$.getJson()$.get(),因为jQuery内部还是将其转为前者

(2)不要对HTTPS站点使用HTTP去发起请求,最好干脆就不要指定(将HTTP或者HTTPS从你的URL中移除)

(3)不要在链接里面嵌参数,请使用专门的参数设置来传递

// 不易阅读的代码
$.ajax({
    url: "something.php?param1=test1&param2=test2",
    //....
});

// 更易阅读
$.ajax({
    url: "something.php",
    data: {
        param1: test1,
        param2: test2
    }
});

(4)尽量指明数据类型以便你自己清楚要处理什么样的数据(见下方会提到的Ajax模板)

(5)对于异步动态加载的内容,最好使用代理来绑定事件处理程序。这样的好处是对于之后动态加载的元素事件同样有效。

$('#parent-container').on('click', 'a', delegatedClickHandlerForAjax);

(6)使用Promise模式

$.ajax({
    //...
}).then(successHandler, failureHandler);

// 抑或
var jqxhr = $.ajax({
    // ...
});
jqxhr.done(successHandler);
jqxhr.fail(failureHandler);

(7)标准的Ajax模板一分。追寻根源

var jqxhr = $.ajax({
    url: url,
    type: 'GET', // 默认为GET,你可以根据需要更改
    cache: true, // 默认为true,但对于script,jsonp类型为false,可以自行设置
    data: {}, // 将请求参数放这里.
    dataType: 'json', // 指定想要的数据类型
    jsonp: 'callback', // 指定回调处理JSONP类型的请求
    statusCode: { // 如果你想处理各状态的错误的话
        404: handler404,
        500: handler500
    }
});
jqxhr.done(successHandler);
jqxhr.fail(failureHandler);

2.7 动画与特效

(1)保持一个始终如一风格统一的动画实现

(2)紧遵用户体验,不要滥用动画特效

  • 使用简洁的显示隐藏,状态切换,滑入滑出等效果来展示元素使用预设值来设置动画的速度'fast','slow',或者400(中等速度)

2.8 插件相关

(1)始终选择一个有良好支持,完善文档,全面测试过并且社区活跃的插件
(2)注意所用插件与当前使用的jQuery版本是否兼容
(3)一些常用功能应该写成jQuery插件。一分jQuery插件的编写模板

2.9链式句法

(1)除了用变量将jQuery选择器返回的结果保存,还可以利用好链式调用。

$("#myDiv").addClass("error").show();

(2)当链式调用多达3次以上或代码因绑定回调略显复杂时,使用换行和适当的缩进来提高代码的可读性。

$("#myLink")
    .addClass("bold")
    .on("click", myClickHandler)
    .on("mouseover", myMouseOverHandler)
    .show();

(3)对于特别长的调用最好还是用变量保存下中间结果来简化代码。

2.10 其他

(1)使用对象字面量来传递参数

// 糟糕:调用了三次attr
$myLink.attr('href', '#').attr('title', 'my link').attr('rel', 'external');

// 不错,只调用了一次attr
$myLink.attr({
    href: '#',
    title: 'my link',
    rel: 'external'
});

(2)不要将CSS与jQuery杂揉

$('#mydiv').css({'color':red, 'font-weight':'bold'}); // 不好
/* 不错 */
.error {
    color: red;
    font-weight: bold;}
$('#mydiv').addClass('error'); 

(3)时刻关注官方Changelog,不要使用摒弃了的方法。点此查看所有废弃的方法
(4)适时地使用原生JavaScript。一些与此有关的性能比较

$("#myId"); // 多少还是会逊色于`document.getElementById("myId")`

REFERENCE

原文:Coding Standards & Best Practices http://lab.abhinayrathore.com/jquery-standards/

Revision: 2015.11.02

使用Pushy实现热更新(1)准备工作

准备工作

注意:该文档为windows7下Android实践随笔。
这里介绍的热更新服务由ReactNative中文网提供,使用之前请先注册
原文请戳这里

首先你应该有一个基于React Native开发的应用,我们把具有package.json的目录叫做你的"应用根目录"。

如果你还没有初始化应用,请参阅开始使用React Native。

所以我们也假设你已经拥有了开发React Native应用的一切环境,包括Node.js、npm、XCode、Android SDK等等。

如果你之前没安装过,你还必须安装Android NDK,并设置环境变量ANDROID_NDK_HOME,指向你的NDK根目录(例如/Users/tdzl2003/Downloads/android-ndk-r10e)。

安装 react-native-update

在你的项目根目录下运行以下命令:

npm install -g react-native-update-cli rnpm
npm install --save react-native-update
rnpm link react-native-update

说明:

npm install -g react-native-update-cli rnpm这一句在每一台电脑上仅需运行一次(因为全局安装)。

rnpm link react-native-update (这句的作用简单的看来就是在项目的Java代码中添加包引用,可以在执行前后查看
MainActivity.java的区别)

mac 可能遇到无读写权限等问题

注意
如果访问极慢或者显示网络失败,请使用淘宝镜像:

npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global

Windows平台请注意

  • 你必须安装python 2.7以及一套C++环境(推荐VS2013或VS2015,VS2010及以前版本不可用)
  • 如果使用VS2015,你需要设置npm config set msvs_version 2015 --global

配置Bundle URL(iOS)

// TODO:IOS 暂未实践,实践后更新文档

在工程target的Build Phases->Link Binary with Libraries中加入libz.tbd、libbz2.1.0.tbd

在你的AppDelegate.m文件中增加如下代码:

// ... 其它代码

#import "RCTHotUpdate.h"

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#if DEBUG
  // 原来的jsCodeLocation
  jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
  jsCodeLocation=[RCTHotUpdate bundleURL];
#endif
  // ... 其它代码
}

配置Bundle URL(Android)

在你的MainActivity中增加如下代码:

// ... 其它代码

import cn.reactnative.modules.update.UpdateContext;

public class MainActivity extends ReactActivity {

    @Override
    protected String getJSBundleFile() {
        return UpdateContext.getBundleUrl(this);
    }
    // ... 其它代码
}

登录与创建应用

在项目根目录(如:D:\Java\AndroidStudio\React-Native\HelloRN)下运行以下命令:

cd /d D:\Java\AndroidStudio\React-Native\HelloRN
pushy login
email: <输入你的注册邮箱>
password: <输入你的密码>

操作示例结果:

C:\Users\ML>cd /d D:\Java\AndroidStudio\React-Native\HelloRN
D:\Java\AndroidStudio\React-Native\HelloRN>pushy login
email: [email protected]
password: ********

Welcome, mlwills.

这会在项目文件夹下创建一个.update文件,注意不要把这个文件上传到GitCVS系统上。
你可以在.gitignore末尾增加一行.update来忽略这个文件。

注意:迄今为止免费用户最多只可以创建3个应用
登录之后可以创建应用。注意iOS平台和安卓平台需要分别创建:

pushy createApp --platform ios
App Name: <输入应用名字>
pushy createApp --platform android
App Name: <输入应用名字>

两次输入的名字可以相同,这没有关系。

如下:

D:\Java\AndroidStudio\React-Native\HelloRN>pushy createApp --platform android
App Name: HelloRN
Created app 1145

D:\Java\AndroidStudio\React-Native\HelloRN>pushy createApp --platform ios
App Name: HelloRN
Created app 1146

如果你已经在网页端或者其它地方创建过应用,也可以直接选择应用:

pushy selectApp --platform android
970 IReactNative
1101 IReactNative
Total 2 android apps
Enter appId: <输入应用前面的编号> 

(如果选取ios应用就改变后面的参数为ios:pushy selectApp --platform ios

选择或者创建过应用后,你将可以在文件夹下看到update.json文件,其内容类似如下形式:

{
    "ios": {
        "appId": 1,
        "appKey": "<一串随机字符串>"
    },
    "android": {
        "appId": 1101,
        "appKey": "<一串随机字符串>"
    }
}
{
    "android": {
        "appId": 1145,
        "appKey": "_fZxhBVRAfsklFcuSv9Z5UoiK_p3kdEs"
    },
    "ios": {
        "appId": 1146,
        "appKey": "DyuRMeip_-vIN4PbP70-t0Ln6iP4BJa6"
    }
}

你可以安全的把update.json上传到GitCVS系统上,与你的团队共享这个文件,它不包含任何敏感信息。当然,他们在使用任何功能之前,都必须首先输入pushy login进行登录。

至此应用的创建/选择就已经成功了。下一步,你需要给代码添加相应的功能,请参阅添加热更新功能

生成带签名的apk

生成带签名的APK

本文是根据生成已签名的APK
在Windows 7 系统上的实践,如果非Windows系统可以查看原文。

生成签名秘钥

在此介绍生成签名秘钥的两种方法(人选其一)

  • 使用keytool生成
  • 使用Android Studio 生成

keytool,一个密钥与证书管理工具,安装Java后可以在JDK的bin可以找到。

使用keytool生成

Android Studio 等IDE自带的生成工具要比命令行方便,如果你安装了Android Studio等工具可以
忽略该方法。

windows在DOS命令行中输入

keytool -genkey -v -keystore app-release-key.keystore -alias app-key-alias -keyalg RSA -keysize 2048 -validity 10000

然后根据提示,输入自己的内容即可,如下所示

C:\Users\ML> keytool -genkey -v -keystore app-release-key.keystore -alias app-key-
alias -keyalg RSA -keysize 2048 -validity 10000
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
  [Unknown]:  mlwills
您的组织单位名称是什么?
  [Unknown]:  GZZTWLKM
您的组织名称是什么?
  [Unknown]:  GZZTWLKM
您所在的城市或区域名称是什么?
  [Unknown]:  昆明
您所在的省/市/自治区名称是什么?
  [Unknown]:  云南/昆明市/盘龙区
该单位的双字母国家/地区代码是什么?
  [Unknown]:  CN
CN=mlwills, OU=GZZTWLKM, O=GZZTWLKM, L=昆明, ST=云南/
昆明市/盘龙区, C=CN是否正确?
  [否]:  是

正在为以下对象生成 2,048 位RSA密钥对和自签名证书 (SHA256withRSA) (有效期为 10,00
0 天):
         CN=mlwills, OU=GZZTWLKM, O=GZZTWLKM, L=昆明,
 ST=云南/昆明市/盘龙区, C=CN
输入 <app-key-alias> 的密钥口令
        (如果和密钥库口令相同, 按回车):
再次输入新口令:
[正在存储app-release-key.keystore]

注意:记得记录相应的秘钥名称、别名、密码,后面将会使用到
完成之后,可以在相应的目录下(示例中为:C:\Users\ML>)找到签名秘钥
app-release-key.keystore

使用Android Studio 生成

步骤如下:

  • (1)打开Android Studio(以2.0版本为例)
  • (2)点击Build-->Generate Signed APK-->Create New
  • (3)选择存储路径和文件名(扩展名为jks),填写其它信息,点击【OK】完成

注意:同样要记住名称、别名和密码(密码太多可以设置成一致)

设置gradle变量

选择一种方法生成秘钥,然后将其拷贝到React Native项目中的android\app\路径下
(如:D:\Java\AndroidStudio\React-Native\HelloRN\android\app

说明:以项目HelloRN为例

打开(HelloRN\android\gradle.properties
添加如下内容(#是注释符)

#以下是秘钥配置信息

#采用keytool生成的keystore秘钥(使用请删除前面的#注释)
#MYAPP_RELEASE_STORE_FILE=app-release-key.keystore
#MYAPP_RELEASE_KEY_ALIAS=app-release-key-alias
#MYAPP_RELEASE_STORE_PASSWORD=yourpassword
#MYAPP_RELEASE_KEY_PASSWORD=yourpassword

#采用Android Studio 生成的jks秘钥
MYAPP_RELEASE_STORE_FILE=app-release-key.jks
MYAPP_RELEASE_KEY_ALIAS=app-release-key-alias
MYAPP_RELEASE_STORE_PASSWORD=yourpassword
MYAPP_RELEASE_KEY_PASSWORD=yourpassword

添加签名到应用的gradle配置文件

注意:可能存在多个gradle配置文件,请注意别找错

打开HelloRN\android\app\build.gradle
找到android{ /*之前已经有很过配置项*/},把以下内容添加到其中:

...
android {
    ...
    defaultConfig { ... }
    // 添加 signingConfigs >>>
    signingConfigs {
        release {
            storeFile file(MYAPP_RELEASE_STORE_FILE)
            storePassword MYAPP_RELEASE_STORE_PASSWORD
            keyAlias MYAPP_RELEASE_KEY_ALIAS
            keyPassword MYAPP_RELEASE_KEY_PASSWORD
        }
    }
    // 添加 signingConfigs <<<
    buildTypes {
        release {
            ...
            // 在buildTypes中添加如下的配置
            signingConfig signingConfigs.release
        }
    }
}
...

示例的完整android配置如下(添加部分做了详细的说明)

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.hellorn"
        minSdkVersion 16
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
        ndk {
            abiFilters "armeabi-v7a", "x86"
        }
    }

    /* add by mlwills@20160520 */
    signingConfigs {
        release {
            storeFile file(MYAPP_RELEASE_STORE_FILE)
            storePassword MYAPP_RELEASE_STORE_PASSWORD
            keyAlias MYAPP_RELEASE_KEY_ALIAS
            keyPassword MYAPP_RELEASE_KEY_PASSWORD
        }
    }
    /* add by mlwills end */

    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "x86"
        }
    }

    buildTypes {
        release {
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            /* add by mlwills@20160520 */
            signingConfig signingConfigs.release
        }
    }

    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
            def versionCodes = ["armeabi-v7a":1, "x86":2]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
            }
        }
    }
}

生成APK包

如果你在android/app下有一个react.gradle

只要在项目的android 目录下运行以下命令:

gradlew assembleRelease

如:cd /d D:\Java\AndroidStudio\React-Native\HelloRN\android && gradlew assembleRelease

打包成功之后就可以在android\app\build\outputs\apk下找到app-release.apk

本示例在D:\Java\AndroidStudio\React-Native\HelloRN\android\app\build\outputs\apk\

如果你希望改变JavaScript代码包或者资源文件被打包的方式(譬如你想改变这些文件存放的目录或者整个工程的文件结构),
你可以读一下android/app/build.gradle看看你可以做什么配置来应用这些修改。

如果你没有react.gradle文件

注意:笔者在践行时没有react.gradle,升级RN之后也没有,而且升级存在风险,请谨慎操作!!!

那我们这样做:

(1)在android/app/src/main/下建立assets文件夹(如果有该文件夹或之前运行过RN创建了该文件夹,可以省略该步骤)

(2)在项目根目录下(D:\Java\AndroidStudio\React-Native\HelloRN\)运行一下命令进行JS打包

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/
C:\Users\ML>cd /d D:\Java\AndroidStudio\React-Native\HelloRN
D:\Java\AndroidStudio\React-Native\HelloRN>react-native bundle --platform androi
d --dev false --entry-file index.android.js --bundle-output android/app/src/main
/assets/index.android.bundle --assets-dest android/app/src/main/res/
...
transformed 359/359 (100%)
[11:37:48] <END>   find dependencies (13471ms)
bundle: start
bundle: finish
bundle: Writing bundle output to: android/app/src/main/assets/index.android.bund
le
bundle: Done writing bundle output
bundle: Copying 5 asset files
bundle: Done copying assets

(3)生成APK

在RN项目的android目录下运行

gradlew assembleRelease

本机执行如下:

cd /d D:\Java\AndroidStudio\React-Native\HelloRN\android && gradlew assembleRelease

至此一个带签名的React Native APK 就打包成功了。

测试应用的发行版本

在把发行版本公布之前,你应该做一次最终测试。输入以下命令可以在设备上安装发行版本:

cd /d D:\Java\AndroidStudio\React-Native\HelloRN\android && gradlew installRelease

注意:

  • installRelease命令只能在你完成了上面的签名配置之后才可以使用。
  • 在执行该命令之前需要连接你的安卓设备。

启用Proguard代码混淆来缩小APK文件的大小(可选,但在实际应用中比较重要)

Proguard是一个Java字节码混淆压缩工具,它可以移除掉React Native Java(和它的依赖库中)中没有被使用到的部分,
最终有效的减少APK的大小。

**重要:**启用Proguard之后,你必须再次全面地测试你的应用。
Proguard有时候需要为你引入的每个原生库做一些额外的配置。参见app/proguard-rules.pro文件。

要启用Proguard,编辑android/app/build.gradle文件:
默认值为false,改为true

/**
 * Run Proguard to shrink the Java bytecode in release builds.
 */
def enableProguardInReleaseBuilds = true

再次生成APK,可以看到原先7.4MB的压缩包变为了6.79MB。(比我想象的要差点!)

React Native 组件一览表

React Native Components

React Native 官方组件一览表(截止至20160520)

官方组件统计

组件类型个数
所有组件32
通用组件19
IOS组件9
Android组件4

官方组件明细

组件说明
ActivityIndicatorIOS加载指示器(菊花)
DatePickerIOS日期选择器
DrawerLayoutAndroid侧边栏
Image图片
ListView列表视图
MapView地图
Modal模态框
Navigator导航不易使用
NavigatorIOSIOS导航各种视图切换就靠它
PickerIOSIOS的下拉控件
Picker普通下拉控件
ProgressBarAndroidAndroid的Loading
ProgressViewIOS进度条UIProgressView
RefreshControl下拉时出现的Loading配合ScrollView使用
ScrollView滚动视图上滑、下滑全靠它
SegmentedControlIOSIOS的单选框
Slider范围选择组件常用数值范围
SliderIOSIOS范围选择组件
StatusBar用于控制应用状态栏的组件
Switch开关
TabBarIOSIOS选项卡常用于首页
TabBarIOS.ItemIOS选项卡项
Text文本组件用于显示文本,文本不能游离在其它组件中
TextInput文本输入框
ToolbarAndroidAndroid工具栏
TouchableHighlight点击触摸时高亮
TouchableNativeFeedback
TouchableOpacity触摸时透明
TouchableWithoutFeedback触摸时无响应
View视图作用类似于Web中的div
ViewPagerAndroidAndroid翻页视图
WebView渲染一个原生的Web视图可以加载html页面

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.