您的位置:首页 > Web前端 > React

React-Native for Android

2015-10-19 14:06 573 查看

React-Native Android

既拥有Native的用户体验、又保留React的开发效率。

  尽管Native开发成本更高,但现阶段Native仍然是必须的,因为Web的用户体验仍无法超越Native:

  ① Native的原生控件有更好的体验;

  ② Native有更好的手势识别;

  ③ Native有更合适的线程模型,尽管Web Worker可以解决一部分问题,但如图像解码、文本渲染仍无法多线程渲染,这影响了Web的流畅性。

  ④ Native能实现更丰富细腻的动画效果,归根结底是现阶段Native具有更好的人机交互体验



图片来自天猫技术:

天猫技术–关于React-Native

1.环境

  React Native只支持在OS X系统, React Native开发的app 要求客户端os >= Android 4.1 (API 16) 和>= iOS 7.0

1.1 工具

Homebrew

Nodejs

nvm

watchman

flow

1.2 SDK 环境要求

Android SDK Build-tools version 23.0.1

Android 6.0 (API 23)

Android Support Repository

1.3 Demo Hello World

$ npm install -g react-native-cli
$ react-native init AwesomeProject
$ cd AwesomeProject/
$ react-native run-android


  相应的会在目录AwesomeProject/android/app下创建Android Studio工程,AwesomeProject/iOS/AwesomeProject.xcodeproj目录中创建XCode工程

注:不管是 iOS 还是 Android,在开发调试阶段,都需要在 Mac 上启动一个 HTTP 服务,称为
Debug Server
,默认运行在 8081 端口,APP 通 Debug Server 加载 js。

2.概念

2.1 Component组件

  React Native 主要是通过 Virtual Dom 来实现显示页面或者页面中的模块。可以通过 React.createClass() 来创建自己的 Dom,在 React 中称之为组件(Component)

1. 创建组件

// Android
var React = require('react-native');
var { DrawerLayoutAndroid, ProgressBarAndroid } = React;

var App = React.createClass({
render: function() {
return (
<DrawerLayoutAndroid
renderNavigationView={() => <Text>React Native</Text>}>
<ProgressBarAndroid />
</DrawerLayoutAndroid>
);
},
});

// iOS
var React = require('react-native');
var { TabBarIOS, NavigatorIOS } = React;

var App = React.createClass({
render: function() {
return (
<TabBarIOS>
<TabBarIOS.Item title="React Native" selected={true}>
<NavigatorIOS initialRoute={{ title: 'React Native' }} />
</TabBarIOS.Item>
</TabBarIOS>
);
},
});


2. 使用组件

  类似 HTML 标准标签

<< MyCustomComponent />



<< MyCustomComponent >

<< /MyCustomComponent>

3. 组件生命周期

  React 组件的数据保存在自己内部的 state 变量中.都有相应回调。

- getInitialState: 获得初始化组件状态,只调用一次.

- componentWillMount: 组件将要加载,只调用一次

- componentDidMount: 组件加载完成并显示出来了,也就是完成了一次绘制,只调用一次

- render: 绘制组件,可能调用多次。

  

4. 自定义组件

  render 函数是必须的,其他可选

var MyCustomComponent = React.createClass({

getInitialState: function() {
// 这里返回一个对象,设置组件的初始化状态,后面就可以通过 this.state 来获得这个对象
return {
key1: data1,
key2: data2,
...
};
},

componentWillMount: function() {
// 这里一般做一些和界面显示无关的初始化操作
},

componentDidMount: function() {
// 这里一般做加载数据的操作
},

render: function() {
// 这是最重要的函数,用来绘制界面,所有的自定义组件,这个函数是必须提供的
return(
<View>
...
</View>
);
},
});


5. 组件数据

  根据组件的状态 state 来绘制动态页面

render: function() {
return(
//把状态中的 key1 的值用 Text 组件直接显示
<Text>{this.state.key1}</Text>
);
}


状态(statu)

  组件的状态(statu) 除了使用 getInitialState 方法来设置初始化状态外,在界面逻辑处理或者事件交互的过程中,

可以调用 this.setState(…) 方法来修改组件的状态值。如果在代码中直接修改 state,React 就会把旧状态和新状态

做一个 diff,找到变化的部分,然后对应找到和这个变化的值关联的界面部分,请求重新绘制这个部分。

属性(Property)

  属性(Property)可以通过 this.props 来直接获取

<View style={{flex: 1}}>


   区别: 一般 属性 表示静态的数据,组件创建后,就基本不变的内容,状态 是动态数据。

3.React Native布局

  React Native 的布局,实用的是 FlexBox 实现,类似网页的 CSS 布局方法

React Native 中的样式长度单位,是逻辑单位,概念和 Android 中的 dp 一样。

示例Demo: 知乎日报客户端

github源码地址

4.Android Studio示例工程概览

   MainActivity 已经针对React Native做了一层封装调用,默认帮我们维护了React Native的生命周期。

import android.app.Activity;
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;
import com.facebook.soloader.SoLoader;

public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {

private ReactInstanceManager mReactInstanceManager;
private ReactRootView mReactRootView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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, "AwesomeProject", null);

setContentView(mReactRootView);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}

@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}

@Override
protected void onPause() {
super.onPause();

if (mReactInstanceManager != null) {
mReactInstanceManager.onPause();
}
}

@Override
protected void onResume() {
super.onResume();

if (mReactInstanceManager != null) {
mReactInstanceManager.onResume(this);
}
}
}


   index.android.js

**
* Sample React Native App
* https://github.com/facebook/react-native */
'use strict';

var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
} = React;

var AwesomeProject = React.createClass({
render: function() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Shake or press menu button for dev menu
</Text>
</View>
);
}
});

var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});

AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);


   package.json 是工程的依赖和元数据配置文件:

{
"name": "AwesomeProject",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node_modules/react-native/packager/packager.sh"
},
"dependencies": {
"react-native": "^0.11.0"
}
}


5.打包发布独立安装包

开发调试的时候必须启动个 JS Server,然后要让手机连接这个 Server。React Native 应用打包的时候,会连接 JS Server 下载一个 ReactNativeDevBundle.js 文件,然后放到应用数据的 files 目录下,就能运行这个 JS 文件了

  目前 iOS 应用可用 react-native bundle 命令进行打包,android暂时没有支持。

针对 Android 的 React Native 应用,可用 react-native-gradle 插件进行打包。该插件灵活配置打包参数,使用 Gradle Task 将资源打包到资源文件夹。

5.1 react-native-gradle 插件

  借助插件 react-native-gradle:com.facebook.react:gradleplugin:1.0.+ 可完成混淆及资源打包。(插件并没有发布到 JCenter 或者 Maven Centry)插件源码github地址

安装: react-native-gradle srain$ gradle install

项目中使用build.gradle配置:

buildscript {
repositories {
mavenLocal()    // 本地依赖
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath 'com.facebook.react:gradleplugin:1.0.+'   // 插件依赖
}
}


app/build.gradle配置:

apply plugin: 'com.facebook.react'

react {
bundleFileName "index.android.bundle"   // assets 目录下 js 文件名
bundlePath "/index.android.bundle"      // js 路径
jsRoot "../"                            // js 源文件位置
packagerHost "localhost:8081"           // debug server 地址
packagerCommand "./node_modules/react-native/packager/packager.sh"  // 打包命令地址

devParams {
skip true
dev true
inlineSourceMap false
minify false
runModule true
}
releaseParams {
skip false
dev false
inlineSourceMap false
minify true
runModule true
}
}


[b]Params参数:[/b]

skip 是否跳过从本地资源加载,从 Debug Server 请求资源

其他四个参数通过 url 传给 Debug Server。

dev: 全局变量 DEV, React Native 核心类库的开发选项

minify: 混淆

inlineSourceMap: 是否加入 source map。默认 false

runModule: 是否在最后以 require(XXX) 的形式加入 module 的入口点。默认 true

require(“AwesomeProject/index.android.js”);

官网地址:https://facebook.github.io/react-native/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 用户体验 React