天天看點

【REACT NATIVE 系列教程之十二】REACT NATIVE(JS/ES)與IOS(OBJECT-C)互動通信

一用到跨平台的引擎必然要有引擎與各平台原生進行互動通信的需要。那麼Himi先講解React Native與iOS之間的通信互動。

       本篇主要分為兩部分講解:(關于其中講解的OC文法等不介紹,不懂的請自行學習)

       1. React Native 通路iOS 

       2. iOS通路React Native

    一:React Native 通路iOS

1. 我們想要JS調用OC函數,就要實作一個“RCTBridgeModule”協定的Objective-C類

是以首先我們先建立一個oc新類,  Himi這裡起名為:TestOJO  (O: object-c, J: javaScript )

2. TestOJO.h

1

2

3

4

5

6

<code>#import &lt;Foundation/Foundation.h&gt;</code>

<code>#import "RCTBridgeModule.h"</code>

<code> </code> 

<code>@interface TestOJO : NSObject  &lt;RCTBridgeModule&gt;</code>

<code>@end</code>

引入:#import “RCTBridgeModule.h”   且使用 &lt;RCTBridgeModule&gt; 接口,

3. 為了實作RCTBridgeModule協定,類需要包含RCT_EXPORT_MODULE()宏(這個宏也可以添加一個參數用來指定在Javascript中通路這個子產品的名字。如果你不指定,預設就會使用這個Objective-C類的名字。)

4. 在TestOJO.m中添加如下:

<code>RCT_EXPORT_MODULE();</code>

<code>//橋接到Javascript的方法傳回值類型必須是void。React Native的橋接操作是異步的,是以要傳回結果給Javascript,必須通過回調或者觸發事件來進行</code>

<code>RCT_EXPORT_METHOD(j2oFun1:(NSString *)dataString dateNumber:(int)dateNumber)</code>

<code>{</code>

<code>    </code><code>NSLog(@</code><code>"js call iOS function j2oFun1\n dataString: %@ |dateNumber :%d"</code><code>,dataString,dateNumber);</code>

<code>}</code>

想要将oc的函數導出給js進行調用,那麼就需要進行聲明。聲明通過RCT_EXPORT_METHOD()宏來實作:

j2oFun1:函數名,後續是兩個參數,分别是NSString 和 int 類型資料。

調用成功後,我們輸出這兩個傳來的值到控制台。

注意:Javascript調用的OC函數,此函數傳回值類型必須是void。由于React Native的橋接操作是異步的,是以要傳回結果給Javascript,必須通過回調參數進行 後續詳細講解。

從js傳來的參數我們可以依靠自動類型轉換的特性,跳過手動的類型轉換(RCTConvert,下面詳細介紹),在定義函數參數類型時,直接寫上對應想要的資料類型,例如NSData等。

5. 下面看js調用的代碼段:

<code>var</code> <code>TestOJO = require(</code><code>'react-native'</code><code>).NativeModules.TestOJO;</code>

<code>TestOJO.j2oFun1(</code><code>'Himi'</code><code>, 12321);</code>

var TestOJO=require(‘react-native’).NativeModules.TestOJO;(将OC注冊進來的子產品取出)

TestOJO.j2oFun1(‘Himi’, 12321);(調用子產品中的對應函數,且将參數進行傳入)

6. 我們來看一段複雜的資料通信

OC 代碼段(導出函數):

7

8

9

10

11

12

<code>#import "RCTConvert.h"</code>

<code>RCT_EXPORT_METHOD(j2oFun2:(NSDictionary *)details)</code>

<code>  </code><code>NSString *name = [RCTConvert NSString:details[@</code><code>"name"</code><code>]];</code>

<code>  </code><code>NSNumber *age = [RCTConvert NSNumber:details[@</code><code>"age"</code><code>]];</code>

<code>  </code><code>NSArray * array =[RCTConvert NSArray:details[@</code><code>"array"</code><code>]];</code>

<code>  </code><code>NSLog(@</code><code>"js call iOS function j2oFun2\n name: %@ | age :%@"</code><code>, name, [age stringValue]);</code>

<code>  </code> 

<code>  </code><code>for</code> <code>(int i = 0; i&lt;[array count]; i++) {</code>

<code>    </code><code>NSLog(@</code><code>"array: 第%d個元素:%@"</code><code>,i,array[i]);</code>

<code>  </code><code>}</code>

需要注意的是,引入了”RCTConvert”類,作用:

RCTConvert提供了一系列輔助函數,用來接收一個JSON值并轉換到原生Objective-C類型或類。

JS代碼段:(調用OC函數)

<code>TestOJO.j2oFun2({</code>

<code>    </code><code>name:</code><code>'Himi'</code><code>,</code>

<code>    </code><code>age:12,</code>

<code>    </code><code>array:[</code>

<code>          </code><code>'hi,Himi'</code><code>,</code><code>'i,m'</code><code>,</code><code>'a array!'</code>

<code>    </code><code>]</code>

<code> </code><code>});</code>

7. 我們下面來利用回調參數來得到通路OC的函數得到其傳回值

<code>RCT_EXPORT_METHOD(j2oCallbackEvent:(NSString *)jsString callback:(RCTResponseSenderBlock)callback)</code>

<code>  </code><code>NSLog(@</code><code>"js call iOS function:  j2oCallbackEvent \n jsString:%@"</code><code>,jsString);</code>

<code>  </code><code>NSArray *events = [[NSArray alloc] initWithObjects:@</code><code>"Himi"</code><code>,@</code><code>"12321"</code><code>, nil];</code>

<code>  </code><code>callback(@[[NSNull </code><code>null</code><code>], events]);</code>

RCTResponseSenderBlock 是種特殊的參數類型——回調函數,通過此參數可以實作當JS通路的OC函數後,并能将此OC函數的傳回值傳遞給JS。

RCTResponseSenderBlock 隻接受一個參數(傳遞給JavaScript回調函數的參數數組)

callback函數:第一個參數是一個錯誤對象(沒有發生錯誤的時候為null),而剩下的部分是函數的傳回值。

下面我們來看JS調用代碼段:

<code>TestOJO.j2oCallbackEvent(</code><code>'Himi'</code><code>,(error,callBackEvents)=&gt;{</code>

<code>   </code><code>if</code> <code>(error) {</code>

<code>       </code><code>console.error(error);</code>

<code>   </code><code>} </code><code>else</code> <code>{</code>

<code>       </code><code>Alert.alert(</code><code>'J2O帶傳回值'</code><code>, </code><code>'數組的三個值:\n[0]:'</code><code>+callBackEvents[0]+</code><code>'\n[1]:'</code><code>+callBackEvents[1]+</code><code>'\n[2]:'</code><code>+callBackEvents[2]);</code>

<code>   </code><code>}</code>

<code>});</code>

二: iOS通路React Native

1.  我們如果想要OC通路JS,給JavaScript發送事件通知,我們需要使用RCTEventDispatcher的函數,與RCTBridge的執行個體

是以我們需要先做準備,TestOJO.h:

<code>#import "RCTEventDispatcher.h"</code>

<code>@synthesize bridge = _bridge;</code>

bridge: 是RCTBridge 的執行個體,且在我們使用的接口 RCTBridgeModule中。

OC通路JS的代碼段:

<code>[self.bridge.eventDispatcher sendAppEventWithName:@</code><code>"eventName"</code> <code>body:@{@</code><code>"name"</code><code>:@</code><code>"Himi"</code><code>,@</code><code>"age"</code><code>: @12}];</code>

第一個參數:事件名

第二個參數(body):傳入的參數

其中@{}是定義不可變的字典的快捷執行個體方式,是以我們也可以改成如下形式:

<code>NSDictionary * direct =@{@</code><code>"name"</code><code>: @</code><code>"Himi"</code><code>,@</code><code>"age"</code><code>: @12};</code>

<code>    </code><code>[self.bridge.eventDispatcher sendAppEventWithName:@</code><code>"eventName"</code> <code>body:direct];</code>

下面來看JS中定義OC調用的函數:

其實所謂OC能響應JS,是JS進行了對應函數的綁定監聽。是以我們需要利用 NativeAppEventEmitter 元件,利用其addListener進行注冊監聽!是以我們需要引入進來這個子產品,

<code>import {</code>

<code>  </code><code>...</code>

<code>  </code><code>NativeAppEventEmitter</code>

<code> </code><code>} from </code><code>'react-native'</code><code>;</code>

<code>var</code> <code>o2cFun = NativeAppEventEmitter.addListener(</code>

<code>  </code><code>'eventName'</code><code>,</code>

<code>  </code><code>(para) =&gt; Alert.alert(</code><code>'被OC觸發'</code><code>,</code><code>'字典資料:\n name:'</code><code>+para.name+</code><code>'\n age:'</code><code>+para.age)</code>

<code>);</code>

var o2cFun : 将綁定好的監聽事件引用交給此變量儲存。

addListener:

第二個參數:響應函數

注意:利用addListener進行監聽,一定要對應有取消監聽!要保持一一對應的好習慣。

且通常取消監聽都在componentWillUnmount函數中進行。如下:

<code>  </code><code>componentWillUnmount(){</code>

<code>    </code><code>o2cFun.remove();</code>

其中對于原理并沒有詳細的介紹,這裡推薦兩篇文章,童鞋們可以詳細的閱讀一下,這裡不贅述:

<a href="http://www.jianshu.com/p/203b91a77174" target="_blank">http://www.jianshu.com/p/203b91a77174</a>

<a href="http://reactnative.cn/docs/0.21/native-modules-ios.html#content" target="_blank">http://reactnative.cn/docs/0.21/native-modules-ios.html#content</a>

下面給出源碼:

TestOJO.h:

<code>//</code>

<code>//  TestOJO.h</code>

<code>//  MyProject</code>

<code>//  Created by Himi on 16/6/2.</code>

<code>//  Copyright  2016年 Facebook. All rights reserved.</code>

TestOJO.m:

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

<code>//  TestOJO.m</code>

<code>#import "TestOJO.h"</code>

<code>//RCTConvert類支援的的類型也都可以使用,RCTConvert還提供了一系列輔助函數,用來接收一個JSON值并轉換到原生Objective-C類型或類。</code>

<code>//本地子產品也可以給JavaScript發送事件通知。最直接的方式是使用eventDispatcher</code>

<code>@implementation TestOJO</code>

<code>//====================================[JS -&gt;  OC]=======================================</code>

<code>//帶回調函數 RCTResponseSenderBlock ,提供将傳回值傳回給js</code>

<code>//RCTResponseSenderBlock 隻接受一個參數-&gt;傳遞給JavaScript回調函數的參數數組</code>

<code>//====================================[OC -&gt;  JS]=======================================</code>

<code>//此函數是為了測試OC-&gt;JS過程,觸發事件的函數</code>

<code>RCT_EXPORT_METHOD(emitterO2J)</code>

<code>  </code><code>[self ocCallJsFun];</code>

<code>- (void)ocCallJsFun</code>

<code>    </code><code>NSDictionary * direct =@{@</code><code>"name"</code><code>: @</code><code>"Himi"</code><code>,@</code><code>"age"</code><code>: @12};</code>

<code>  </code><code>//  [self.bridge.eventDispatcher sendAppEventWithName:@"eventName" body:@{@"name":@"Himi",@"age": @12}];</code>

Main.js:

57

58

59

60

61

62

63

64

65

66

67

68

<code>import React, { Component } from </code><code>'react'</code><code>;</code>

<code>  </code><code>View,</code>

<code>  </code><code>Text,</code>

<code>  </code><code>StyleSheet,</code>

<code>  </code><code>Image,</code>

<code>  </code><code>Alert,</code>

<code>  </code><code>NativeAppEventEmitter,</code><code>//引用NativeAppEventEmitter元件進行監聽Native端派發的事件</code>

<code>// 千萬不要忘記忘記取消訂閱, 通常在componentWillUnmount函數中實作。</code>

<code>// o2cFun.remove();</code>

<code>export </code><code>default</code> <code>class Main extends Component {</code>

<code>    </code><code>constructor(props) {</code>

<code>        </code><code>super</code><code>(props);</code>

<code>        </code><code>this</code><code>.state = {</code>

<code>      </code><code>selectedTab:</code><code>'home'</code>

<code>    </code><code>};</code>

<code>    </code><code>}</code>

<code>  </code><code>render() {</code>

<code>     </code><code>return</code> <code>(</code>

<code>         </code><code>&lt;View style={{flex: 1, alignItems: </code><code>'center'</code><code>}}&gt;</code>

<code>         </code><code>&lt;Text style={styles.himiTextStyle}&gt;Himi React Native 系列教程&lt;/Text&gt;</code>

<code>         </code><code>&lt;Text</code>

<code>           </code><code>onPress={()=&gt;{</code>

<code>              </code><code>TestOJO.j2oFun1(</code><code>'Himi'</code><code>, 12321);</code>

<code>              </code><code>TestOJO.j2oFun2({</code>

<code>                </code><code>name:</code><code>'Himi'</code><code>,</code>

<code>                </code><code>age:12,</code>

<code>                </code><code>array:[</code>

<code>                  </code><code>'hi,Himi'</code><code>,</code><code>'i,m'</code><code>,</code><code>'a array!'</code>

<code>                </code><code>]</code>

<code>              </code><code>});</code>

<code>              </code><code>TestOJO.j2oCallbackEvent(</code><code>'Himi'</code><code>,(error,callBackEvents)=&gt;{</code>

<code>                </code><code>if</code> <code>(error) {</code>

<code>                  </code><code>console.error(error);</code>

<code>                </code><code>} </code><code>else</code> <code>{</code>

<code>                  </code><code>Alert.alert(</code><code>'J2O帶傳回值'</code><code>, </code><code>'數組的三個值:\n[0]:'</code><code>+callBackEvents[0]+</code><code>'\n[1]:'</code><code>+callBackEvents[1]+</code><code>'\n[2]:'</code><code>+callBackEvents[2]);</code>

<code>                </code><code>}</code>

<code>           </code><code>}}</code>

<code>           </code><code>style={styles.himiTextStyle}&gt;JS -&gt; OC</code>

<code>         </code><code>&lt;/Text&gt;</code>

<code>              </code><code>TestOJO.emitterO2J();</code>

<code>           </code><code>style={styles.himiTextStyle}&gt;JS -&gt; OC -&gt; JS</code>

<code>        </code><code>&lt;/View&gt;</code>

<code>     </code><code>);</code>

<code>};</code>

<code>var</code> <code>styles = StyleSheet.create({</code>

<code>  </code><code>himiTextStyle:{</code>

<code>    </code><code>backgroundColor:</code><code>'#eee'</code><code>,</code>

<code>    </code><code>color:</code><code>'#f00'</code><code>,</code>

<code>    </code><code>fontSize:30,</code>

<code>    </code><code>marginTop:70,</code>

<code>  </code><code>},</code>

下面是運作效果:(點選看動态圖,主要看示範過程與控制台輸出哦!)

<a href="http://www.himigame.com/wp-content/uploads/2016/06/user918.gif" target="_blank"></a>

注意:

1.點選JS-&gt;OC 後,會調用三個函數哦

2.點選JS-&gt;OC-&gt;JS, 先是通過JS-&gt;OC的臨時函數,觸發OC-&gt;JS的過程!

本文轉自 xiaominghimi 51CTO部落格,原文連結:http://blog.51cto.com/xiaominghimi/1786162,如需轉載請自行聯系原作者

繼續閱讀