• A-Fu Design
  • 前端設計
    • jQuery 套件
    • HTML 5
  • 關於A-Fu
  • 隱私權政策
  • 聯絡A-Fu
Google+ facebook twitter

A-Fu Design

A-Fu Design

Facebook Open Source React Native


應用擴展程序

通過應用擴展程序,您可以在主應用之外提供自定義功能和內容。 iOS上有不同類型的應用擴展,它們都包含在App Extension編程指南中。在本指南中,我們將簡要介紹如何利用iOS上的應用擴展程序。

內存在擴展中使用

由於這些擴展程序是在常規應用程序沙箱之外加載的,因此很可能會同時加載其中幾個應用程序擴展程序。正如您所料,這些擴展具有較小的內存使用限制。在開發應用擴展程序時請記住這些。我們強烈建議您在實際設備上測試您的應用程序,在開發應用程序擴展時更是如此:開發人員經常發現他們的擴展程序在iOS模擬器中工作得很好,只是為了獲得用戶報告他們的擴展程序沒有加載到實際設備。

我們強烈建議您觀看Conrad Kramer關於擴展內存使用的討論,以了解有關此主題的更多信息。


今日小部件

Today小部件的內存限制為16 MB。實際上,使用React Native的今日小部件實現可能不可靠,因為內存使用率往往過高。您可以判斷您的Today小部件是否超出內存限制,如果它產生消息'無法加載':
始終確保在真實設備中測試您的應用擴展程序,但請注意,這可能還不夠,尤其是在處理Today小部件時。調試配置的構建更有可能超出內存限制,而發布配置的構建不會立即失敗。我們強烈建議您使用Xcode的Instruments來分析您的實際內存使用情況,因為您的發布配置版本很可能非常接近16 MB的限制。在這種情況下,通過執行常見操作(例如從API獲取數據)很容易超過16 MB的限制。

要試驗React Native Today小部件實現的限制,請嘗試在 react-native-today-widget 中擴展示例項目。

其他應用擴展程序

其他類型的應用擴展程序比Today小部件具有更大的內存限制。例如,自定義鍵盤擴展名限制為48 MB,共享擴展名限制為120 MB。使用React Native實現此類應用擴展更加可行。一個概念證明示例是 react-native-ios-share-extension。



Share
Tweet
Pin
Share
No 意見
Facebook Open Source React Native
Native 和 React Native之間的通信

在“與現有應用程序集成指南”和“本機UI組件”指南中,我們將學習如何在本機組件中嵌入React Native,反之亦然。當我們混合使用Native和React Native組件時,我們最終會發現需要在這兩個世界之間進行通信。其他指南中已經提到了實現這一目標的一些方法。本文總結了可用的技術。

介紹


React Native 的靈感來自 React,因此信息流的基本思想是相似的。 React 中的流程是單向的。我們維護組件的層次結構,其中每個組件僅依賴於其父級和它自己的內部狀態。我們使用屬性執行此操作:數據以自上而下的方式從父級傳遞給其子級。如果祖先組件依賴於其後代的狀態,則應傳遞回調以供後代使用以更新祖先。

相同的概念適用於 React Native。只要我們在框架內構建我們的應用程序,我們就可以使用屬性和回調驅動我們的應用程序。但是,當我們混合使用 React Native 和本機組件時,我們需要一些特殊的跨語言機制來允許我們在它們之間傳遞信息。

屬性

屬性是跨組件通信的最簡單方式。因此,我們需要一種方法將屬性從本機傳遞到React Native,從React Native傳遞到本機。

將屬性從本機傳遞到React Native
為了在本機組件中嵌入React Native視圖,我們使用RCTRootView。 RCTRootView是一個包含React Native應用程序的UIView。它還提供本機端和託管應用程序之間的接口。

RCTRootView有一個初始化程序,允許您將任意屬性傳遞給React Native應用程序。 initialProperties參數必須是NSDictionary的一個實例。字典在內部轉換為頂級JS組件可以引用的JSON對象。
NSArray *imageList = @[@"http://foo.com/bar1.png",
                       @"http://foo.com/bar2.png"];

NSDictionary *props = @{@"images" : imageList};

RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                 moduleName:@"ImageBrowserApp"
                                          initialProperties:props];
import React from 'react';
import {
  AppRegistry,
  View,
  Image
} from 'react-native';

class ImageBrowserApp extends React.Component {
  renderImage(imgURI) {
    return (
      <Image source={{uri: imgURI}} />
    );
  }
  render() {
    return (
      <View>
        {this.props.images.map(this.renderImage)}
      </View>
    );
  }
}

AppRegistry.registerComponent('AwesomeProject', () => ImageBrowserApp);
AppRegistry.registerComponent('AwesomeProject',()=> ImageBrowserApp);
RCTRootView還提供了一個讀寫屬性appProperties。設置appProperties後,將使用新屬性重新呈現React Native應用程序。僅當新更新的屬性與先前的屬性不同時才執行更新。
NSArray *imageList = @[@"http://foo.com/bar3.png",
                       @"http://foo.com/bar4.png"];

rootView.appProperties = @{@"images" : imageList};
可以隨時更新屬性。但是,必須在主線程上執行更新。你在任何線程上使用getter。

一次只能更新幾個屬性。我們建議您將其構建到自己的包裝器中。
注意:目前,在更新prop後,將不會調用頂級RN組件的JS函數componentWillReceiveProps和componentWillUpdateProps。但是,您可以在componentWillMount函數中訪問新的props。

將屬性從React Native傳遞到本機

本文詳細介紹了暴露本機組件屬性的問題。簡而言之,在自定義本機組件中使用RCT_CUSTOM_VIEW_PROPERTY宏導出屬性,然後在React Native中使用它們,就好像該組件是普通的React Native組件一樣。

屬性限制

跨語言屬性的主要缺點是它們不支持回調,這將允許我們處理自下而上的數據綁定。想像一下,由於JS操作,您希望從本機父視圖中刪除一個小RN視圖。道具沒有辦法做到這一點,因為信息需要自下而上。

雖然我們有一種跨語言的回調(這裡描述),但這些回調並不總是我們需要的。主要問題是它們不打算作為屬性傳遞。相反,這種機制允許我們從JS觸發本機操作,並在JS中處理該操作的結果。

跨語言交互的其他方式(事件和本機模塊)

如前一章所述,使用屬性有一些限制。有時屬性不足以推動我們的應用程序的邏輯,我們需要一個提供更多靈活性的解決方案。本章介紹React Native中可用的其他通信技術。它們可用於內部通信(在RN和RN中的本機層之間)以及外部通信(在RN與應用程序的“純本機”部分之間)。

React Native使您可以執行跨語言函數調用。您可以從JS執行自定義本機代碼,反之亦然。不幸的是,根據我們正在努力的方面,我們以不同的方式實現相同的目標。對於native - 我們使用事件機制來安排在JS中執行處理函數,而對於React Native,我們直接調用由本機模塊導出的方法。

從本機(事件)調用React Native函數

本文詳細介紹了事件。請注意,使用事件不能保證執行時間,因為事件是在單獨的線程上處理的。

事件很強大,因為它們允許我們更改React Native組件而無需引用它們。但是,使用它們時可能會遇到一些陷阱:

  • 由於事件可以從任何地方發送,因此可以在項目中引入意大利面風格的依賴項。
  • 事件共享命名空間,這意味著您可能會遇到一些名稱衝突。不會靜態檢測到衝突,這使得它們難以調試。
  • 如果您使用相同React Native組件的多個實例,並且希望將它們與事件的視角區分開來,則可能需要引入標識符並將它們與事件一起傳遞(您可以使用本機視圖的reactTag作為標識符) 。
我們在React Native中嵌入native時使用的常見模式是使本機組件的RCTViewManager成為視圖的委託,通過網橋將事件發送回JavaScript。這使相關的事件調用保持在一個地方。

從React Native調用本機函數(本機模塊)

本機模塊是JS中可用的Objective-C類。通常,每個JS橋都會創建一個每個模塊的實例。他們可以將任意函數和常量導出到React Native。本文詳細介紹了它們。

原生模塊是單例的事實限制了嵌入環境中的機制。假設我們在本機視圖中嵌入了React Native組件,並且我們想要更新本機父視圖。使用本機模塊機制,我們將導出一個函數,該函數不僅包含預期的參數,還包含父本機視圖的標識符。標識符將用於檢索對要更新的父視圖的引用。也就是說,我們需要在模塊中保持從標識符到本機視圖的映射。

儘管此解決方案很複雜,但它在RCTUIManager中使用,RCTUIManager是一個管理所有React Native視圖的內部React Native類。

本機模塊也可用於將現有本機庫公開給JS。地理位置庫是這個想法的活生生的例子。
警告:所有本機模塊共享相同的命名空間。創建新名稱時要注意名稱衝突。

佈局計算流程

在集成native和React Native時,我們還需要一種方法來整合兩個不同的佈局系統。本節介紹常見的佈局問題,並簡要介紹解決這些問題的機制。

React Native 中嵌入的本機組件的佈局

本文將介紹此案例。基本上,由於我們所有的本機反應視圖都是UIView的子類,因此大多數樣式和大小屬性都可以像開箱即用的那樣工作。

嵌入本機的React Native組件的佈局

使用固定大小的React Native內容

最簡單的方案是當我們有一個具有固定大小的React Native應用程序時,本機方面已知。特別是,全屏React Native視圖屬於這種情況。如果我們想要一個較小的根視圖,我們可以顯式設置RCTRootView的框架。
例如,要使RN app 200(邏輯)像素為高,並且託管視圖的寬度為寬,我們可以:
// SomeViewController.m

- (void)viewDidLoad
{
  [...]
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:appName
                                            initialProperties:props];
  rootView.frame = CGRectMake(0, 0, self.view.width, 200);
  [self.view addSubview:rootView];
}
當我們有一個固定大小的根視圖時,我們需要尊重它在JS方面的界限。換句話說,我們需要確保React Native內容可以包含在固定大小的根視圖中。確保這一點的最簡單方法是使用flexbox佈局。如果使用絕對定位,並且React組件在根視圖的邊界外可見,則會與本機視圖重疊,從而導致某些功能出現意外行為。例如,'TouchableHighlight'不會突出顯示根視圖邊界之外的觸摸。

通過重新設置其frame屬性來動態更新根視圖的大小是完全正確的。 React Native將負責內容的佈局。

具有靈活大小的 React Native 內容

在某些情況下,我們想要呈現最初未知大小的內容。假設大小將在JS中動態定義。我們有兩個解決這個問題的方法。

  1. 您可以將React Native視圖包裝在ScrollView組件中。這可以保證您的內容始終可用,並且不會與本機視圖重疊。
  2. React Native允許您在JS中確定RN應用程序的大小,並將其提供給託管RCTRootView的所有者。然後,所有者負責重新佈置子視圖並保持UI一致。我們通過RCTRootView的靈活模式實現了這一目標。
RCTRootView 支持4種不同大小的靈活模式:
// RCTRootView.h

typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
  RCTRootViewSizeFlexibilityNone = 0,
  RCTRootViewSizeFlexibilityWidth,
  RCTRootViewSizeFlexibilityHeight,
  RCTRootViewSizeFlexibilityWidthAndHeight,
};
RCTRootViewSizeFlexibilityNone 是默認值,它使根視圖的大小固定(但仍可以使用setFrame更新:)。其他三種模式允許我們跟踪React Native內容的大小更新。例如,將模式設置為RCTRootViewSizeFlexibilityHeight將導致React Native測量內容的高度並將該信息傳遞回RCTRootView的委託。可以在委託中執行任意操作,包括設置根視圖的框架,以使內容適合。只有在內容大小發生變化時才會調用委託。
警告:在JS和native中創建一個靈活的維度會導致未定義的行為。例如 - 當您在託管RCTRootView上使用RCTRootViewSizeFlexibilityWidth時,不要使頂級React組件的寬度靈活(使用flexbox)。
我們來看一個例子。
// FlexibleSizeExampleView.m

- (instancetype)initWithFrame:(CGRect)frame
{
  [...]

  _rootView = [[RCTRootView alloc] initWithBridge:bridge
  moduleName:@"FlexibilityExampleApp"
  initialProperties:@{}];

  _rootView.delegate = self;
  _rootView.sizeFlexibility = RCTRootViewSizeFlexibilityHeight;
  _rootView.frame = CGRectMake(0, 0, self.frame.size.width, 0);
}

#pragma mark - RCTRootViewDelegate
- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
{
  CGRect newFrame = rootView.frame;
  newFrame.size = rootView.intrinsicContentSize;

  rootView.frame = newFrame;
} 
在示例中,我們有一個包含根視圖的FlexibleSizeExampleView視圖。我們創建根視圖,初始化它並設置委託。代表將處理大小更新。然後,我們將根視圖的大小靈活性設置為RCTRootViewSizeFlexibilityHeight,這意味著每次React Native內容更改其高度時都將調用rootViewDidChangeIntrinsicSize:方法。最後,我們設置根視圖的寬度和位置。請注意,我們也設置了高度,但它沒有效果,因為我們使高度RN依賴。

您可以在此處查看示例的完整源代碼。 
可以動態更改根視圖的大小靈活性模式。更改根視圖的靈活性模式將安排佈局重新計算,並且一旦知道內容大小,將調用委託rootViewDidChangeIntrinsicSize:方法。
注意:React Native佈局計算在特殊線程上執行,而本機UI視圖更新在主線程上完成。這可能會導致本機和React Native之間的UI不一致。這是一個已知問題,我們的團隊正在努力同步來自不同來源的UI更新。
注意:在根視圖成為某些其他視圖的子視圖之前,React Native不會執行任何佈局計算。如果要隱藏React Native視圖直到其尺寸已知,請將根視圖添加為子視圖並使其最初隱藏(使用UIView的隱藏屬性)。然後在委託方法中更改其可見性。



Share
Tweet
Pin
Share
No 意見
Facebook Open Source React Native


在模擬器上運行

啟動模擬器


一旦初始化了React Native項目,就可以在新創建的項目目錄中運行react-native run-ios。 如果一切設置正確,您應該會很快看到您的新應用在iOS模擬器中運行。

指定設備

您可以使用--simulator標誌指定模擬器應運行的設備,然後將設備名稱指定為字符串。 默認為“iPhone 6”。 如果你想在iPhone 4s上運行你的應用程序,只需運行react-native run-ios --simulator =“iPhone 4s”。

設備名稱對應於Xcode中可用的設備列表。 您可以通過從控制台運行xcrun simctl list devices來檢查可用設備。




Share
Tweet
Pin
Share
No 意見
Facebook Open Source React Native


鏈接資源庫

並非每個應用程序都使用所有本機功能,並且包括支持所有這些功能的代碼會影響二進製文件大小...但我們仍然希望在您需要時輕鬆添加這些功能。

考慮到這一點,我們將許多這些功能作為獨立的靜態庫公開。

對於大多數庫而言,它將像拖動兩個文件一樣簡單,有時需要第三步,但不多於此。

我們隨React Native提供的所有庫都存儲在存儲庫根目錄中的Libraries文件夾中。其中一些是純JavaScript,你只需要它。其他庫也依賴於一些本機代碼,在這種情況下,您必須將這些文件添加到您的應用程序中,否則一旦您嘗試使用該庫,應用程序就會拋出錯誤。

以下是鏈接包含本機代碼的庫的幾個步驟

自動鏈接

步驟 1

安裝具有本機依賴項的庫:
$ npm install <library-with-native-dependencies> --save
注意:--save或--save-dev標誌對於此步驟非常重要。 React Native將根據package.json文件中的依賴項和devDependencies鏈接您的lib。

步驟 2

鏈接您的本機依賴項:
$ react-native link
完成!所有具有本機依賴關係的庫都應成功鏈接到您的iOS / Android項目。
注意:如果您的iOS項目使用CocoaPods(包含Podfile)並且鏈接庫具有podspec文件,則react-native鏈接將使用Podfile鏈接庫。要支持非平凡的Podfiles,請添加#在此行註釋下添加新pod,以添加到您希望添加pod的位置。

手動鏈接

步驟 1

如果庫具有本機代碼,則其文件夾中必須有.xcodeproj文件。將此文件拖到Xcode上的項目中(通常在Xcode上的Libraries組下);

步驟 2

單擊您的主項目文件(代表.xcodeproj的文件)選擇Build Phases並將靜態庫從您要導入的Library內的Products文件夾拖到Link Binary With Libraries

步驟 3

並非每個圖書館都需要這一步,您需要考慮的是:

在編譯時我是否需要知道庫的內容?

這意味著,您是在本機端還是僅在JavaScript中使用此庫?如果你只是在JavaScript中使用它,那麼你很高興!

如果你確實需要從native調用它,那麼我們需要知道庫的頭文件。要實現這一點,您必須轉到項目的文件,選擇構建設置並蒐索標題搜索路徑。在那裡你應該包括你的圖書館的路徑。 (此文檔過去建議使用遞歸,但不再推薦使用它,因為它可能導致細微的構建失敗,尤其是對於CocoaPods。)



Share
Tweet
Pin
Share
No 意見
Older Posts

About me

還在努力掙扎中的工程師

Follow Us

  • Google+
  • facebook
  • twitter

Categories

Accordion Animation AutoComplete CSS Calendar Canvas Carousel Charts Color DatePicker Effects Facebook API Forms Gallery HTML5 Menu Mootools Prototype React images jQuery javascripts lightbox 前端技術 統計圖表 網頁設計

Recent Posts

  • jQuery Gantt Chart 在網頁上繪製甘特圖的 jQuery 套件
  • Kalendae 一個不依賴任何框架的日期選擇器
  • AJAX progress bar 非同步傳輸結合 XML 資料回傳
  • Line Developer Day 2018 內部技術與實務分享
  • NCC資安初級認證?只有這 5 款通過

Sponsor

Facebook

Blog Archive

  • 9月 2025 (27)
  • 8月 2025 (62)
  • 7月 2025 (62)
  • 6月 2025 (58)
  • 4月 2025 (48)
  • 3月 2025 (60)
  • 2月 2025 (51)
  • 1月 2025 (56)
  • 12月 2024 (61)
  • 11月 2024 (60)
  • 10月 2024 (54)
  • 9月 2024 (55)
  • 8月 2024 (42)
  • 7月 2024 (40)
  • 6月 2024 (19)
  • 9月 2023 (3)
  • 4月 2023 (2)
  • 2月 2023 (1)
  • 12月 2021 (1)
  • 1月 2019 (11)
  • 12月 2018 (31)
  • 11月 2018 (31)
  • 10月 2018 (31)
  • 9月 2018 (30)
  • 8月 2018 (31)
  • 7月 2018 (3)
  • 2月 2018 (1)
  • 4月 2015 (1)
  • 9月 2014 (1)
  • 2月 2014 (1)
  • 7月 2013 (1)
  • 2月 2013 (2)
  • 1月 2013 (1)
  • 12月 2012 (12)
  • 11月 2012 (81)
  • 10月 2012 (64)

Created with by ThemeXpose | Distributed by Blogger Templates