React Native 在現有項目中的探路

移動開發中,native開發性能和效果上無疑是最好的。html

可是在衆多的狀況下,native開發並非最優的選擇。當需求常常改動的時候,當預算有限的時候,當deadline很近的時候,native開發的成本也就體現出來了。node

這時候,webview開始大放異彩,快速開發、無需從新發布版本、人員成本低的特色就顯現出來了。(這裏不指hybrid)。react

當使用WebView後,就會逐漸發現,用戶體驗變得一塌糊塗,長時間的loading、操做dom形成的性能問題等等等等···linux

react native出現後,開闢的一條新的道路。android

 

#0 分析一下下

公司如今的產品經歷了2個大的版本更新後(純native和部分WebView),如今要經歷第三個重大版本的升級了。但此次版本出現了一些狀況。ios

版面所有更新、人員有限、預算有限、開發時間短。這就是面臨的問題所在。git

hybrid是一整套的將html轉爲native的開發方式,但使用此方法將會面臨的問題是:所有項目須要推翻重作、沒有作過此類開發、沒有經驗。這對咱們來講是一個很大的冒險。否決!github

後續討論後,使用native進行框架方面的搭建,大量使用webview進行過渡,開始逐步接入react native。web

這樣的好處就是基礎內容仍然在可控範圍內,可大量重複使用以前的代碼。大量使用webview是爲了保證項目能夠在規定時間內趕工完成···純屬無奈之舉。shell

使用react native是爲了後續逐步替代webview而進行的。因爲在rn方面沒有很足的經驗,只能一步一步的來,不敢一次性引入太多。

rn的好處就是在於能夠在已有的項目中接入開發,而不像hybrid那樣,須要所有替換纔可使用。這樣就能夠保證當rn遇到坑沒法解決的時候,能夠用較少的代價替換回native,保證項目的可控性。

 

#1 react native開發服務器

開發時,仍是使用服務器來裝載內容較爲方便。這裏使用的是ubuntu server 14.04。

這裏仍是提一句,rn是如何工做的。

在開發時,咱們的框架是這樣的:

當正式發佈進入到生產環境時,開發服務器上全部的js文件將會被編譯成包的形式,直接嵌入到客戶端內。這時,已經再也不須要開發服務器的支持了。(熱更新後續繼續寫)

 

#2 詳細的搭建步奏

#2.0  服務器搭建

因爲資金有限,因此直接搞的虛擬機,安裝的ubuntu server,基礎設置:安裝的node版本是v5.8.0。

這裏就不詳細的講解node如何安裝了···你們自行查找···網上不少···

首先安裝Watchman和Flow

git clone https://github.com/facebook/watchman.git

cd watchman

git checkout v4.1.0 # the latest stable release

./autogen.sh

./configure

make

sudo make install

 

sudo npm install -g flow-bin

具體方法詳見:https://facebook.github.io/react-native/docs/getting-started-linux.html#getting-started-on-linux (後面的安裝android不須要)

而後建立一個存放代碼的目錄,好比個人目錄是:/var/react/tykReact

切換到此目錄下,執行下面語句進行初始化設置。

npm init

若是此語句在設置時不太會用,可在目錄下建立package.json文件,文件中的內容以下:

{
  "name": "tykReact",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node_modules/react-native/packager/packager.sh"
  },
  "author": "LunaGao",
  "license": "MIT",
  "dependencies": {
    "react-native":"^0.20.0"
  }
}

注意:

1. dependencies下的"react-native":"^0.20.0"是必須的,直接npm install react-native安裝在後續會出現問題。

2. scripts下的"start": "node_modules/react-native/packager/packager.sh"是爲了啓動使用的。(也能夠不用)

 

此時,就能夠執行如下語句進行下載react了。

npm install

這個時間比較長,須要耐心等待(我下載了1個小時...)。固然,最好加上sudo,以避免出現沒有權限等問題。

當安裝好後,建立兩個文件:index.ios.js和index.android.js。這是用來測試使用的。

index.ios.js

'use strict';

import React, {
  Text,
  View
} from 'react-native';

var styles = React.StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'red'
  }
});

class SimpleApp extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>This is a simple application.</Text>
      </View>
    )
  }
}

React.AppRegistry.registerComponent('TestView', () => SimpleApp);

index.android.js

'use strict';

import React, {
  Text,
  View
} from 'react-native';

class MyAwesomeApp extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.hello}>Hello, World</Text>
      </View>
    )
  }
}
var styles = React.StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

React.AppRegistry.registerComponent('TestView', () => MyAwesomeApp);

兩個文件的代碼並不相同,這是直接從

https://facebook.github.io/react-native/docs/embedded-app-android.html#add-js-to-your-app

https://facebook.github.io/react-native/docs/embedded-app-ios.html#create-your-react-native-app 

複製而來。

至此,目錄下應該是以下的樣子:

請忽略116221-這樣的文件和11f83243da86022a90031e1ca9d758bc,這些是服務啓動後自動生成的。npm-debug.log.4046290474這個是錯誤的日誌文件。

沒問題後,咱們開始啓動服務,執行以下語句:

npm start

正常的狀況以下圖所示:

此時,打開瀏覽器,輸入地址進行訪問(192.168.0.203是個人服務器地址,須要替換成實際的地址,本機運行可直接使用localhost):

http://192.168.0.203:8081/index.ios.bundle?platform=ios

http://192.168.0.203:8081/index.android.bundle?platform=android

當返回相似於下圖的內容時,證實服務器已經正常啓動了(返回的內容其實不少···)。

#2.1 ios集成

建立一個測試用的ios項目,如:react-test

使用pod進行集成,首先要使用npm安裝react-native(使用命令:npm install react-native),這個過程可能有點久,而後修改pod文件內容以下:

#platform :ios,'9.0'

use_frameworks!

 

target "react-test" do

  pod 'React', :path => './node_modules/react-native', :subspecs => [

  'Core',

  'RCTImage',

  'RCTNetwork',

  'RCTText',

  'RCTWebSocket',

  # Add any other subspecs you want to use in your project

  ]

end

pod如何使用這裏就不作過多解釋了。

而後,在storyboard中拖入一個view,把view的class改成ReactTestView。而後建立ReactTestView,繼承自UIView。

ReactTestView.h

//
//  ReactTestView.h
//  react-test
//
//  Created by Luna Gao on 16/3/3.
//  Copyright © 2016年 gao.luna.com. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "RCTRootView.h"

@interface ReactTestView : UIView

@end

ReactTestView.m

//
//  ReactTestView.m
//  react-test
//
//  Created by Luna Gao on 16/3/3.
//  Copyright © 2016年 gao.luna.com. All rights reserved.
//

#import "ReactTestView.h"

@implementation ReactTestView


- (void)awakeFromNib {
    NSString *urlString = @"http://192.168.0.203:8081/index.ios.bundle?platform=ios";
    NSURL *jsCodeLocation = [NSURL URLWithString:urlString];
//    NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"TestView" initialProperties:nil launchOptions:nil];
    [self addSubview:rootView];
    rootView.frame = self.bounds;
}

@end

而後就能夠跑起來了。運行效果以下圖(樣子可能不同,個人storyboard中增長了tab bar controller):

#2.2 Android集成

內容較多,請參考https://facebook.github.io/react-native/docs/embedded-app-android.html#prepare-your-app

注:這裏時須要作 prepare-your-app 和 add-native-code 這兩段中的內容。

將onCreate方法修改成:

super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mReactRootView = (ReactRootView) findViewById(R.id.test_js);
        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, "TestView", null);

在activity_main.xml文件中增長一個ReactRootView,id命名爲:test_js。代碼以下:

<com.facebook.react.ReactRootView
        android:id="@+id/test_js"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/test_text"/>

請注意:在AndroidManifest.xml文件中增長

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>

此時運行代碼,界面以下:

在命令行中執行:adb shell input keyevent 82

將彈出以下對話框:

點擊Dev Settings,點擊 Debug server host & port for device 選項以下圖:

輸入ip地址和端口號,如:192.168.0.203:8081,點擊ok。

返回到應用打開頁面,再次使用adb shell input keyevent 82命令,點擊Reload JS,從新加載js文件。此時就會正常顯示界面了。以下圖:

 

#3 如何發佈

發佈時,咱們須要先編譯js文件。

在服務器中切換到剛剛的目錄下(如/var/react/tykReact),執行以下兩個命令:

sudo react-native bundle --minify --entry-file index.ios.js --bundle-output /tmp/ios.jsbundle --platform ios

sudo react-native bundle --minify --entry-file index.android.js --bundle-output /tmp/android.jsbundle --platform android

會在/tmp目錄下出現兩個文件:

ios.jsbundle 和 android.jsbundle。

將這兩個文件分別放入到ios項目和android asset目錄下,以下圖:

  

修改ios代碼:

ReactTestView.m

//    NSString *urlString = @"http://192.168.0.203:8081/index.ios.bundle?platform=ios";
//    NSURL *jsCodeLocation = [NSURL URLWithString:urlString];
    NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"ios" withExtension:@"jsbundle"];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"TestView" initialProperties:nil launchOptions:nil];
    [self addSubview:rootView];
    rootView.frame = self.bounds;

注意:這裏須要將ios.jsbundle文件加入到項目中。

修改android代碼:

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mReactRootView = (ReactRootView) findViewById(R.id.test_js);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("android.jsbundle")
                .setJSMainModuleName("android")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();
        mReactRootView.startReactApplication(mReactInstanceManager, "TestView", null);

 

至此,項目就能夠不在依賴開發服務器而直接使用安裝包進行運行了~

另:debug模式須要在正式發佈的時候取消掉。

相關文章
相關標籤/搜索