1. 程式人生 > >react-native入門,編寫靜態頁面,整合原生專案

react-native入門,編寫靜態頁面,整合原生專案

React-Native技術調研

0.前提:

搭建環境:https://reactnative.cn/docs/getting-started/,
分mac/win/linux,平臺分android/ios。

1.建立一個新專案

使用rn建立一個專案和把rn技術整合到一個現有的原生專案是有差別的。

//建立和執行一個rn專案:
react-native init AwesomeProject
cd AwesomeProject
react-native run-ios

編譯和執行需要一段時間...耐心等待..根據rn版本的不同,ios虛擬機器也不不同,比如最新的0.57版本的是iphoneX,低版本的rn預設創造的ios虛擬機器就老一點。

注意官網中特別提到:

!!!注意!!!:init 命令預設會建立最新的版本,而目前最新的 0.45 及以上版本需要下載 boost
等幾個第三方庫編譯。這些庫在國內即便FQ也很難下載成功,導致很多人無法執行iOS專案!!!中文網在論壇中提供了這些庫的國內下載連結。如果你嫌麻煩,又沒有對新版本的需求,那麼可以暫時建立0.44.3的版本。

我在rn版本0.57.5,react-cli版本2.0.1直接init建立專案沒有遇到以上問題。

幾個常用操作

  1. cmd+r 重新整理,可配置熱更新,調出選單enable liveload
  2. cmd+d 調出選單

2.試著用RN寫一個靜態頁面

https://github.com/ZhangMingZhao1/react-native-pratice/tree/master/earphone_guide

3.整合到一個原生專案

這裡以一個rn整合到ios object-c為例,現實中這種情況可能也更多一些。

a.

用xcode新建一個單頁面應用,語言選擇object-c,名字為ReactNativeDemo,在專案根目錄下,新建ReactNative資料夾,用於存放跟reactnative相關檔案。(後面簡稱rn)

b.

在rn資料夾中新建一個package.json,內容為:

{
  "name": "ReactNativeDemo",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "dependencies": {
    "react": "16.0.0",
    "react-native": "0.51.0"
  }
}

注意版本嚴格規定

c.

進入rn資料夾,npm install,在rn資料夾新建index.js,以前版本是inex.ios.js。
內容為:

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

class ScoresView extends React.Component {
    render() {
      var contents = this.props['scores'].map((score) => (
        <Text key={score.name}>
          {score.name}:{score.value}
          {'\n'}
        </Text>
      ));
      return (
        <View style={styles.container}>
          <Text style={styles.highScoresTitle}>2048 High Scores!</Text>
          <Text style={styles.scores}>{contents}</Text>
        </View>
      );
    }
  }
  
  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#FFFFFF',
    },
    highScoresTitle: {
      fontSize: 20,
      textAlign: 'center',
      margin: 10,
    },
    scores: {
      textAlign: 'center',
      color: '#333333',
      marginBottom: 5,
    },
  });
  
// 註冊元件,程式入口
// 第一個引數:註冊模組名稱,這裡親測不和專案名一致也可以,但是好多資料說名字要和專案名一致
// 第二個引數:函式,此函式返回元件類名,程式啟動就會自動去載入這個元件
AppRegistry.registerComponent('App', () => ScoresView);

d.

進入專案根目錄,安裝cocoapods,

brew install cocoapods

我的mac下會報個錯,在一個檔案下沒有許可權寫入,而homebrew現在禁止使用sudo執行,根據提示的指令可以收回那個檔案的許可權,複製貼上執行就好。

安裝好後,在根目錄使用pod init,在生成的Podfile中內容改為:

source 'https://github.com/CocoaPods/Specs.git'
react_native_path = './ReactNative/node_modules/react-native'
platform :ios, ‘9.0’
use_frameworks!

target 'ReactNativeDemo' do
# 'node_modules'目錄一般位於根目錄中
# 但是如果你的結構不同,那你就要根據實際路徑修改下面的`:path`
pod 'React', :path => react_native_path, :subspecs => [
'Core',
#'BatchedBridge', # 0.45 版本以後需要新增
'CxxBridge',
'DevSupport', # 如果RN版本 >= 0.43,則需要加入此行才能開啟開發者選單
'RCTText',
'RCTImage',
'RCTNetwork',
'RCTWebSocket', # 這個模組是用於除錯功能的
# 在這裡繼續新增你所需要的模組
]
# 如果你的RN版本 >= 0.42.0,則加入下面這行
pod 'yoga', :path => react_native_path + '/ReactCommon/yoga'
# Third party deps
pod 'DoubleConversion', :podspec => react_native_path + '/third-party-podspecs/DoubleConversion.podspec'
pod 'GLog', :podspec => react_native_path + '/third-party-podspecs/GLog.podspec'
pod 'Folly', :podspec => react_native_path + '/third-party-podspecs/Folly.podspec'

end

這個檔案類似npm的package.json,記錄了所需檔案的依賴,所以下一步就是

pod install

e.

在總ios專案中修改http的安全策略,在info.plist加上:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

f.

用xcode開啟專案,在Main.storyboard拖入一個按鈕,在ViewController.m中加入標頭檔案:

#import <React/RCTRootView.h>

再增加一個按鈕的跳轉方法:

- (IBAction)pushToReactNativeView:(id)sender {
    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
    
    RCTRootView *rootView =
    [[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                                moduleName: @"App"
                         initialProperties:
     @{
       @"scores" : @[
               @{
                   @"name" : @"Alex",
                   @"value": @"42"
                   },
               @{
                   @"name" : @"Joel",
                   @"value": @"10"
                   }
               ]
       }
                             launchOptions: nil];
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view = rootView;
    [self presentViewController:vc animated:YES completion:nil];
}

可能會出現加載出錯,這是因為pod install安裝的檔案沒有載入進來,重啟xcode專案,重新開啟專案即可。
然後把ViewController.m檔案中的#import <fishhook/fishhook.h> 改為 #import "fishhook.h",不然後面執行可能會報錯。

g.

給這個按鈕和這個方法繫結起來,進入keyboard,按住 ctrl,點選按鈕會出現一個箭頭,指向左上角的ViewContrller,可出現一個框,選擇剛才寫的pushToReactNativeView方法,會在右下角看到關聯了。
這部可詳見iOS學習之基礎控制元件新增和事件繫結,推薦一個連結:https://www.jianshu.com/p/6eb302a62956

h.

進入到rn資料夾,npm start 啟動node伺服器,這時會進入dev狀態,動態打包。回到xcode,執行專案,點選按鈕,就會看到跳轉到rn寫的頁面。

4.RN打包給原生專案使用

a.

在rn專案根目錄中建立release_ios 資料夾,(打包必須建立資料夾)具體可以自己命名,作為資源目標的輸出檔案目錄。
在根目錄下執行打包命令:

react-native bundle --entry-file index.js --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/

會看到release_ios下多出assets資料夾(如果有圖片),和兩個jsbindle檔案.

b.

將main.jsbundle和assets拖入Xcode的專案導航面板中,選擇預設匯入即可(位置和裡面的資料夾同級)
在這裡插入圖片描述

修改上面的ViewController,m,
在這裡插入圖片描述

將埠動態引入改為本地,讓React Native去使用我們剛才匯入的jsbundle,這樣以來我們就擺脫了對本地nodejs伺服器的依賴。當然也可以將jsbundle 放到自己的遠端伺服器中,更換遠端的伺服器檔案就可以載入jsbundle,為了提高效能我們可以在本地做一次快取。@後面是自己打包檔案的名字不加字尾。

c.

ios app的打包就可以看官網了:https://developer.apple.com/support/app-store-connect/

5.留下的疑問,待繼續研究

  1. npm start後打包的檔案是在哪裡放著的,找了一下沒找到,難道和webpack dev一樣使用了memory-fs-js,把臨時打包檔案動態寫進了記憶體裡嗎?
  2. 大家可以補充..etc