React?Native與iOS?OC之間的交互示例詳解

目錄 前置準備 RN 傳值給 iOS 方法 1 正常傳值給原生 方法 2 傳遞回調函數 方法 3 獲取 promise 回調 方法 3 獲取 promise 的同步方式 iOS 傳值給 RN 端 初始的數據提供 添加監聽事件 總結 前置
目錄
  • 前置準備
  • RN 傳值給 iOS
    • 方法 1 正常傳值給原生
    • 方法 2 傳遞回調函數
    • 方法 3 獲取 promise 回調
    • 方法 3 獲取 promise 的同步方式
  • iOS 傳值給 RN 端
    • 初始的數據提供
    • 添加監聽事件
  • 總結

    前置準備

    首先最好了解一點關于 oc 的語法知識,不然很多都是看不懂的

    創建聲明文件?nativeModule.h

    #import <Foundation/Foundation.h>
    #import <React/RCTBridgeModule.h>
    @interface nativeModule : NSObject <RCTBridgeModule>
    @end

    創建文件?nativeModule.m

    #import <Foundation/Foundation.h>
    #import "nativeModule.h"
    @interface nativeModule ()
    @end
    @implementation nativeModule
    @end

    這是添加完文件后的結構目錄

    關于 interface 的區別:.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);
    }
    @end

    RN 代碼:

    import { Button, NativeModules } from 'react-native'
    const { nativeModule } = NativeModules
    <Button title={'傳 2 個參數給 native'} onPress={() => {
        nativeModule.addHelloWord('你的名字', '位置:浙江')
    }}/>

    點擊此按鈕的作用,就是將?'你的名字', '位置:浙江'?這 2 個字符串傳遞到了原生端

    方法 2 傳遞回調函數

    在 .m 文件中添加:

    // 只接受一個參數——傳遞給 JavaScript 回調函數的參數數組。
    RCT_EXPORT_METHOD(checkIsRoot:(RCTResponseSenderBlock)callback) {
      NSArray *array = @[@"string", @"number"];
      callback(array);
    }

    在 RN 中添加代碼:

    <Button title={'js 傳一個回調給 native,回調中收到一個數組'} onPress={() => {
        nativeModule.checkIsRoot((str: string, num: string) => {
          console.log(str, num)
        })
    }}/>

    這是在 RN 中 給原生端傳遞了一個回調函數,用來解決,部分操作完成后的回調,?如果 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的參數,回調的錯誤信息
    RCT_EXPORT_METHOD(getHBDeviceUniqueID: (RCTPromiseResolveBlock)resolve
                      rejecter:(RCTPromiseRejectBlock)reject) {
      // 要執行的任務
      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?的執行他是一個 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?使用此方法會將代碼變成同步狀態

    iOS 傳值給 RN 端

    初始的數據提供

    在?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 提供的數據,這里我們通過 context 來傳遞數據
    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 端傳來的初始數據{JSON.stringify(images)}</Text>

    添加監聽事件

    在 .m 文件中添加代碼:

    // 可供監聽的事件名稱
    - (NSArray<NSString *> *)supportedEvents
    {
      return @[@"EventReminder"];
    }
    RCT_EXPORT_METHOD(postNotificationEvent:(NSString *)name)
    {
      NSLog(@"calendarEventReminderReceived");
        [self sendEventWithName:@"EventReminder" body:@{@"name": name}];;
    }
    - (void)calendarEventReminderReceived:(NSNotification *)notification
    {
      // 這是官網的例子
      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('這是監聽的EventReminder事件回復', reminder.name)
          }
        )
        return () => {
          subscription.remove()
        }
    }, [])
    <Button title={'js 監聽事件,讓 native 給 js 發通知'} onPress={() => {
        nativeModule.postNotificationEvent('test')
    }}/>
    <Button title={'js 監聽事件,讓 native 給 js 發通知 send'} onPress={() => {
        nativeModule.Send()
    }}/>
    {
        msg.map((item, index) => {
          return <Text key={item + index}>item:{item}</Text>
        })
    }

    關于?postNotificationEvent?方法是屬于最簡單的使用, 在原生端調用?sendEventWithName?就可以傳遞數據給 RN 的監聽

    而另一個方法?Send?和?calendarEventReminderReceived?,一個是來自于官網的實例 講的是從?NSNotification獲取數據,?Send?是傳遞數據給?calendarEventReminderReceived

    關于監聽的優化, 這個官網上也有,有空可以看下,就是在 .m 文件中添加下列代碼:

    @implementation nativeModule
    {
      bool hasListeners;
      // 一個局部變量
    }
    -(void)startObserving {
      hasListeners = YES;
    }
    -(void)stopObserving {
      hasListeners = NO;
    }
    // 在發送監聽的添加判斷,如果有監聽才發送,有效減少橋接代碼的調用
    if (hasListeners) { 
        [self sendEventWithName:@"EventReminder" body:@{@"name": name}];;
    }

    總結

    上述代碼的庫:?https://github.com/Grewer/lea...

    關于原生端和 RN 端的交互基本就是這些了,當然原生端還有更多,更復雜的操作,比如進程什么的,如果想寫橋接方法,這個也會碰到很多,不過掌握了上面這些,對于一些三方 SDK 的調用是夠用了

    以上就是React Native與iOS OC之間的交互示例詳解的詳細內容,更多關于React Native與iOS OC交互的資料請關注技圈網其它相關文章!

    聲明:所有內容來自互聯網搜索結果,不保證100%準確性,僅供參考。如若本站內容侵犯了原著者的合法權益,可聯系我們進行處理。
    發表評論
    更多 網友評論0 條評論)
    暫無評論

    返回頂部

    主站蜘蛛池模板: 在线观看午夜亚洲一区| 婷婷综合五月天| 色老头永久免费网站| 中文字幕av无码不卡免费| 免费看h片网站| 国产黄大片在线观看| 校园亚洲春色另类小说合集| 99rv精品视频在线播放| 久久久久777777人人人视频| 免费看美女隐私全部| 国产精品白丝AV网站| 最近中文国语字幕在线播放| 美女的尿口免费| 91香蕉国产线观看免费全集| 久久香蕉国产线看观看99| 可以**的网址| 国产精品另类激情久久久免费| 欧美日产国产亚洲综合图区一| 丰满少妇作爱视频免费观看| 国产女人的高潮国语对白| 欧美老妇bbbwwbbww| 一个人看的www在线观看免费| 又粗又硬又大又爽免费观看 | 精品国产日韩亚洲一区二区| 久久久国产精品亚洲一区| 四虎永久在线精品免费观看地址| 无码精品a∨在线观看中文 | 2一8一teesex| 亚洲欧美自拍另类图片色| 国产精品高清尿小便嘘嘘| 明星ai人脸替换造梦在线播放| 成人国产在线24小时播放视频| 亚洲人成人无码网www国产| 国产真人无遮挡作爱免费视频| 欧美日韩精品一区二区三区高清视频 | 日本深夜福利19禁在线播放| 爱看精品福利视频观看| 国产小视频免费观看| 精品国产免费人成网站| 中国大白屁股ass| 精品久久久久久无码免费|