react native學習:iOS原生模組的封裝與調用,reactios
1.前言
上一篇文章介紹封裝Android原生模組,今天將介紹如何封裝ios原生模組供React native調用。在React Native中,ios平台原生模組是一個實現了RCTBridgeModule協議的Objective-C類,其中RCT是ReaCT的縮寫。這裡會涉及到一些Objective-C的代碼編寫,不過不用擔心,有一定的ios開發的基礎當然更好,如果你之前從未接觸使用過Objective-C,可能有些文法理解起來較為困難,但這並不妨礙閱讀,本文用編程世界裡最經典的HelloWorld執行個體來介紹ios原生模組的封裝。但如果以後想封裝更為複雜的ios原生平台模組,掌握Objective-C或者Swift的文法還是必須的。
2.建立模組類
在..\ExerciseProject\ios\ExerciseProject目錄下建立HelloWorld.h和HelloWorl.m檔案,或使用Xcode開啟..\ExerciseProject\ios\ExerciseProject.xcodeproj檔案,建立HelloWorld類,會自動產生HelloWorld.h和HelloWorl.m檔案。.h標頭檔包含了類的介面,.m檔案中實現了具體的功能。首先看HelloWorld.h:
#import @interface HelloWorld : NSObject @end
這裡匯入了RCTBridgeModule.h標頭檔,RCTBridgeModule是React Native提供的與iOS原生通訊的橋接實現。接著定義了HelloWorld類繼承於NSObject並實現了RCTBridgeModule介面。
再來看HelloWorld.m:
#import "HelloWorld.h"#import "RCTLog.h"@implementation HelloWorldRCT_EXPORT_MODULE();RCT_EXPORT_METHOD(hello:(NSString *)name){ RCTLogInfo(@"Hello %@ from IOS", name);}@end
第一行匯入了相應的.h檔案,由於後面需要使用RCTLogInfo輸出日誌到應用台,這裡匯入了RCTLog.h。@implementation與@end之間是HelloWorld的具體實現。通過RCT_EXPORT_MODULE()宏匯出此原生模組供React Native介面調用,而RCT_EXPORT_METHOD()宏來實現要給Javascript使用的方法。
3.在javascript端使用
為了使當前封裝的模組在JavaScript中可以方便使用,通常會把該原生模組封裝成JavaScript模組。這樣可以省下每次訪問組件都要加入NativeModules的步驟,不過該步驟不是必須的。
本例中在\ExerciseProject\src\12_nativeapi\中建立一個HelloWorldIOS.js檔案
let { NativeModules } = require('react-native');module.exports = NativeModules.HelloWorld;
然後在別的JavaScript檔案代碼中就可以如下進行訪問:
import HelloWorldIOS from './HelloWorldIOS';...HelloWorldIOS.hello('Jack');
具體在JavaScript檔案中的調用方法執行個體代碼如下:
import React, { Component } from 'react';import { AppRegistry, StyleSheet, Text, View,} from 'react-native';import HelloWorldIOS from './HelloWorldIOS';export default class HelloWorldIOSDemo extends Component { onPress(){ HelloWorldIOS.hello('Jack'); } render() { return ( ); }}
4.參數類型說明
上面例子中我們傳入了string類型的參數,實際應用中還可能需要各種類型的參數。RCT_EXPORT_METHOD 支援所有標準JSON類型。具體如下:
string (NSString) number (NSInteger, float, double, CGFloat, NSNumber) boolean (BOOL, NSNumber) array (NSArray) 包含本列表中任意類型 object (NSDictionary) 包含string類型的鍵和本列表中任意類型的值 function (RCTResponseSenderBlock)
除此以外,任何RCTConvert類支援的類型也都可以使用。RCTConvert是React Native提供的一個類型轉換庫。例如在上面提到的支援的類型中沒有時間類型,如果我們需要傳遞時間即可通過RCTConvert進行類型轉換。
RCTConvert的使用具體可見下例:
步驟如前面2、3小節,先建立DateIOS.h
#import #import @interface DateIOS : NSObject@end
再建立DateIOS.m
#import "DateIOS.h"@implementation DateIOSRCT_EXPORT_MODULE();RCT_REMAP_METHOD(compareDate, date1:(nonnull NSNumber *)d1 date2:(nonnull NSNumber *)d2){ NSDate* dt1 = [RCTConvert NSDate:d1]; NSDate* dt2 = [RCTConvert NSDate:d2]; NSComparisonResult result = [dt1 compare:dt2]; switch(result){ case NSOrderedAscending: { NSLog(@"compare result %@",@"start time < end time"); } case NSOrderedDescending: { NSLog(@"compare result %@",@"start time > end time"); } }}@end
在javascript端使用
import React, { Component } from 'react';import { AppRegistry, StyleSheet, Text, View, Button, DatePickerIOS, NativeModules} from 'react-native';export default class DateIOSDemo extends Component { constructor(){ super(); this.state = {startDate: new Date(), endDate: new Date()}; } onPressDateCompare() { let dateCompare = NativeModules.DateIOS; dateCompare.printDate(this.state.startDate.getTime(), this.state.endDate.getTime()); } onStartDateChange(date) { this.setState({startDate: date}); } onEndDateChange(date) { this.setState({endDate: date}); } render() { return ( ); }}
上例中由於不能在橋接通道裡傳遞Date對象,所以需要把日期轉化成字串或數字來傳遞。在ios端通過如下方式進行轉換:
NSDate* dt1 = [RCTConvert NSDate:d1];
在javascript端將日期以unix時間戳記形式傳遞:
let dateCompare = NativeModules.DateIOS; dateCompare.printDate(this.state.startDate.getTime(), this.state.endDate.getTime());
也可以以ISO-8601的字串形式傳遞:
let dateCompare = NativeModules.DateIOS; dateCompare.printDate(this.state.startDate.toISOString(), this.state.endDate.toISOString());
這兩種方式都會被轉換為正確的NSDate類型。但如果提供一個不合法的值,例如一個Array,則程式會報錯。
以上是關於iOS原生模組的封裝與調用的一個簡單介紹。