React?Native與iOS?OC之間的交互示例詳解
前置準備
首先最好了解一點關于 oc 的語法知識,不然很多都是看不懂的
創(chuàng)建聲明文件 nativeModule.h
#import <Foundation/Foundation.h> #import <React/RCTBridgeModule.h> @interface nativeModule : NSObject <RCTBridgeModule> @end
創(chuàng)建文件 nativeModule.m
#import <Foundation/Foundation.h> #import "nativeModule.h" @interface nativeModule () @end @implementation nativeModule @end

這是添加完文件后的結構目錄
關于 interface 的區(qū)別:.h里面的@interface,它是供其它Class調用的。它的@property和functions,都能夠被其它Class“看到”(public)
而.m里面的@interface,在OC里叫作Class Extension,是.h文件中@interface的補充。但是.m文件里的@interface,對外是不開放的,只在.m文件里可見(private)
因此,我們將對外開放的方法、變量放到.h文件中,而將不想要對外開放的變量放到.m文件中(.m文件的方法可以不聲明,直接用)。
RN 傳值給 iOS
方法 1 正常傳值給原生
在 .m 文件中添加方法:
// 省略上面的代碼
@implementation nativeModule
// 這句代碼是必須的 用來導出 module, 這樣才能在 RN 中訪問 nativeModule這個 module
RCT_EXPORT_MODULE();
// 接收字符串
RCT_EXPORT_METHOD(addHelloWord:(NSString *)name location:(NSString *)location)
{
NSLog(@"%@,%@", name, location);
}
@endRN 代碼:
import { Button, NativeModules } from 'react-native'
const { nativeModule } = NativeModules
<Button title={'傳 2 個參數(shù)給 native'} onPress={() => {
nativeModule.addHelloWord('你的名字', '位置:浙江')
}}/>點擊此按鈕的作用,就是將 '你的名字', '位置:浙江' 這 2 個字符串傳遞到了原生端
方法 2 傳遞回調函數(shù)
在 .m 文件中添加:
// 只接受一個參數(shù)——傳遞給 JavaScript 回調函數(shù)的參數(shù)數(shù)組。
RCT_EXPORT_METHOD(checkIsRoot:(RCTResponseSenderBlock)callback) {
NSArray *array = @[@"string", @"number"];
callback(array);
}在 RN 中添加代碼:
<Button title={'js 傳一個回調給 native,回調中收到一個數(shù)組'} onPress={() => {
nativeModule.checkIsRoot((str: string, num: string) => {
console.log(str, num)
})
}}/>這是在 RN 中 給原生端傳遞了一個回調函數(shù),用來解決,部分操作完成后的回調, 如果 callback 多次調用 RN 會報錯
方法 3 獲取 promise 回調
在 .m 文件中添加代碼:
@interface nativeModule ()
@property (nonatomic) RCTPromiseResolveBlock normalResolve;
@property (nonatomic) RCTPromiseRejectBlock normalReject;
@property (nonatomic) NSInteger num;
@end
// 這是一個計時器
-(void)startTime: (NSArray*) data{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSArray *events =@[@"Promise ",@"test ",@" array"];
if (events) {
self.normalResolve(events);
[timer invalidate];
} else {
[timer invalidate];
NSError *error=[NSError errorWithDomain:@"我是回調錯誤信息..." code:101 userInfo:nil];
self.normalReject(@"no_events", @"There were no events", error);
}
}];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
// 回調給RN的參數(shù),回調的錯誤信息
RCT_EXPORT_METHOD(getHBDeviceUniqueID: (RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
// 要執(zhí)行的任務
self.normalResolve = resolve;
self.normalReject = reject;
[self performSelectorOnMainThread:@selector(startTime:) withObject: [NSArray arrayWithObjects: @"1", @"2", nil] waitUntilDone:YES];
}在 RN 中添加代碼:
<Button title={'native傳一個 promise 給 JS'} onPress={() => {
nativeModule.getHBDeviceUniqueID().then((arr: string[]) => {
console.log('resolve', arr)
}).catch((err: string) => {
console.error(err)
})
}}/>nativeModule.getHBDeviceUniqueID 的執(zhí)行他是一個 promise,可以獲取原生端的回調, 其實和方法 2 差不多
方法 3 獲取 promise 的同步方式
在 .m 文件中添加:
// 這是一個計時器2
-(void)startTime2: (NSArray*) data{
NSLog(@"data%@",data);
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"%d", (int)self.num);
self.num = self.num + 1;
NSLog(@"%d", (int)self.num);
if (self.num > 4) {
[timer invalidate];
NSLog(@"end");
self.normalResolve(data);
}
}];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
// RCT_REMAP_METHOD 與RCT_EXPORT_METHOD相同,但是該方法是在JS線程上從JS同步調用的,可能會返回結果。
// 同步可能會有性能問題 建議除了 promise 以外都別使用
RCT_REMAP_METHOD(findEvents,
findEventsWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
self.normalResolve = resolve;
self.normalReject = reject;
self.num = 0;
[self performSelectorOnMainThread:@selector(startTime2:) withObject: [NSArray arrayWithObjects: @"1", @"2", nil] waitUntilDone:YES];
}在 RN 端添加代碼:
<Button title={'native傳一個 promise 給 JS2'} onPress={() => {
nativeModule.findEvents().then((arr: string[]) => {
console.log('resolve', arr)
}).catch((err: string) => {
console.error(err)
})
}}/>方法 4 和方法 3 大體一致,但是有一點不同,就是 RCT_REMAP_METHOD 使用此方法會將代碼變成同步狀態(tài)
iOS 傳值給 RN 端
初始的數(shù)據(jù)提供
在 appDelegate.m 文件中添加代碼:
NSArray *imageList = @[@"http://foo.com/bar1.png",
@"http://foo.com/bar2.png"];
NSDictionary *props = @{@"images" : imageList};
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"learn" initialProperties:props];
// 這一行代碼原本就有,不同點在于 initialProperties:props在 RN 端寫入:
// 重寫 APP , images就是 iOS 提供的數(shù)據(jù),這里我們通過 context 來傳遞數(shù)據(jù)
export default class App extends React.Component<{ images: string[] }> {
render() {
return <NativeProps.Provider value={this.props.images}>
<AppContainer/>
</NativeProps.Provider>
}
}
// 在 hooks 里簡單的使用
const images = useContext(NativeProps);
<Text>這是從 native 端傳來的初始數(shù)據(jù){JSON.stringify(images)}</Text>添加監(jiān)聽事件
在 .m 文件中添加代碼:
// 可供監(jiān)聽的事件名稱
- (NSArray<NSString *> *)supportedEvents
{
return @[@"EventReminder"];
}
RCT_EXPORT_METHOD(postNotificationEvent:(NSString *)name)
{
NSLog(@"calendarEventReminderReceived");
[self sendEventWithName:@"EventReminder" body:@{@"name": name}];;
}
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
// 這是官網(wǎng)的例子
NSLog(@"calendarEventReminderReceived");
NSString *eventName = notification.userInfo[@"name"];
[self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
}
RCT_EXPORT_METHOD(Send){
NSDictionary *dict = @{@"name" : @"veuimyzi"};
NSNotification *notification = [[NSNotification alloc] initWithName:@"EventReminder" object:nil userInfo:dict] ;
[self calendarEventReminderReceived:notification];
}在 RN 中添加代碼:
const ManagerEmitter = new NativeEventEmitter(nativeModule)
const [msg, setMsg] = useState([])
// hooks 中的使用,類似于 componentDidMount 生命周期
useEffect(() => {
const subscription = ManagerEmitter.addListener(
'EventReminder',
(reminder) => {
setMsg(prevState => {
return prevState.concat(reminder.name)
})
console.log('這是監(jiān)聽的EventReminder事件回復', reminder.name)
}
)
return () => {
subscription.remove()
}
}, [])
<Button title={'js 監(jiān)聽事件,讓 native 給 js 發(fā)通知'} onPress={() => {
nativeModule.postNotificationEvent('test')
}}/>
<Button title={'js 監(jiān)聽事件,讓 native 給 js 發(fā)通知 send'} onPress={() => {
nativeModule.Send()
}}/>
{
msg.map((item, index) => {
return <Text key={item + index}>item:{item}</Text>
})
}關于 postNotificationEvent 方法是屬于最簡單的使用, 在原生端調用 sendEventWithName 就可以傳遞數(shù)據(jù)給 RN 的監(jiān)聽
而另一個方法 Send 和 calendarEventReminderReceived ,一個是來自于官網(wǎng)的實例 講的是從 NSNotification獲取數(shù)據(jù), Send 是傳遞數(shù)據(jù)給 calendarEventReminderReceived
關于監(jiān)聽的優(yōu)化, 這個官網(wǎng)上也有,有空可以看下,就是在 .m 文件中添加下列代碼:
@implementation nativeModule
{
bool hasListeners;
// 一個局部變量
}
-(void)startObserving {
hasListeners = YES;
}
-(void)stopObserving {
hasListeners = NO;
}
// 在發(fā)送監(jiān)聽的添加判斷,如果有監(jiān)聽才發(fā)送,有效減少橋接代碼的調用
if (hasListeners) {
[self sendEventWithName:@"EventReminder" body:@{@"name": name}];;
}總結
上述代碼的庫: https://github.com/Grewer/lea...
關于原生端和 RN 端的交互基本就是這些了,當然原生端還有更多,更復雜的操作,比如進程什么的,如果想寫橋接方法,這個也會碰到很多,不過掌握了上面這些,對于一些三方 SDK 的調用是夠用了
以上就是React Native與iOS OC之間的交互示例詳解的詳細內(nèi)容,更多關于React Native與iOS OC交互的資料請關注腳本之家其它相關文章!
相關文章
react 報錯Module build failed: Browserslis
這篇文章主要介紹了react 報錯Module build failed: BrowserslistError: Unknown browser query `dead`問題的解決方法,需要的朋友可以參考下2023-06-06
react16.8.0以上MobX在hook中的使用方法詳解
這篇文章主要為大家介紹了react16.8.0以上MobX在hook中的使用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07
使用react context 實現(xiàn)vue插槽slot功能
這篇文章主要介紹了使用react context 實現(xiàn)vue插槽slot功能,文中給大家介紹了vue的slot的實現(xiàn)方法,需要的朋友可以參考下2019-07-07
react使用useImperativeHandle示例詳解
這篇文章主要為大家介紹了react使用useImperativeHandle示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09
React實現(xiàn)antdM的級聯(lián)菜單實例
這篇文章主要為大家介紹了React實現(xiàn)antdM的級聯(lián)菜單實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10

