react-native与原生iOS的交互

参考文档:https://www.reactnative.cn/docs/native-modules-ios

有时候 App 需要访问平台 API,但 React Native 可能还没有相应的模块封装;或者你需要复用 Objective-C、Swift 或 C++代码,而不是用 JavaScript 重新实现一遍;又或者你需要实现某些高性能、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。

我们把 React Native 设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果 React Native 还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。

本文是关于如何封装原生模块的高级向导,我们假设您已经具备 Objective-C 或者 Swift,以及 iOS 核心库(Foundation、UIKit)的相关知识。
话不多讲开始撸代码

OC代码的实现

创建一个文件继承于 RCTEventEmitter 实现协议 RCTBridgeModule

.h文件

//
//  CalendarManager.h
//  AppDemo
//
//

#import 
#import 
#import 
NS_ASSUME_NONNULL_BEGIN

@interface CalendarManager : RCTEventEmitter

@end

NS_ASSUME_NONNULL_END

.m

//
//  CalendarManager.m
//  AppDemo
//
//

#import "CalendarManager.h"
#import //调用输出的方法
#import 

@interface CalendarManager ()
@end

@implementation CalendarManager
/**
 *为了实现RCTBridgeModule协议,你的类需要包含RCT_EXPORT_MODULE()宏。这个宏也可以添加一个参数用来指定在 JavaScript 中访问这个模块的名字。如果你不指定,默认就会使用这个 Objective-C 类的名字。如果类名以 RCT 开头,则 JavaScript 端引入的模块名会自动移除这个前缀。
 */
RCT_EXPORT_MODULE()
#pragma mark - 注册方法addEvent
/**
 *你必须明确的声明要给 JavaScript 导出的方法,否则 React Native 不会导出任何方法。声明通过RCT_EXPORT_METHOD()宏来实现:
 *导出到 JavaScript 的方法名是 Objective-C 的方法名的第一个部分。React Native 还定义了一个RCT_REMAP_METHOD()宏,它可以指定 JavaScript 方法名。因为 JavaScript 端不能有同名不同参的方法存在,所以当原生端存在重载方法时,可以使用这个宏来避免在 JavaScript 端的名字冲突。
 *我们需要把事件的时间交给原生方法。我们不能在桥接通道里传递 Date 对象,所以需要把日期转化成字符串或数字来传递
 */
RCT_EXPORT_METHOD(addEvent:(NSString*)name Location:(NSString*)location date:(NSString*)ISO8601DateString){
  RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
  NSDate  *date = [RCTConvert NSDate:ISO8601DateString];
  NSLog(@"接收到的消息为 name = %@ loction = %@ date = %@",name,location,date);
//调用时间发射器发送消息给React-native
  [self calendarEventReminderReceived:[NSNotification notificationWithName:@"sendToRN" object:self userInfo:@{
    @"name":@"sendToRN"
  }]];
}
#pragma mark - 注册方法addDic
/**
 *RCTResponseSenderBlock只接受一个参数——传递给 JavaScript 回调函数的参数数组。在上面这个例子里我们用 Node.js 的常用习惯:第一个参数是一个错误对象(没有发生错误的时候为 null),而剩下的部分是函数的返回值。
 */
RCT_EXPORT_METHOD(addDic:(NSString*)name Details:(NSDictionary*)details callback:(RCTResponseSenderBlock)callBack){
  NSString * address = [RCTConvert NSString:details[@"address"]];
  NSDate * time = [RCTConvert NSDate:details[@"time"]];
  NSString * mark = [RCTConvert NSString:details[@"mark"]];
  NSLog(@"获取到的内容是 name = %@ time = %@ address = %@ 备注=%@",name,time,address,mark);
  callBack(@[[NSNull null],@[@"我接受到你的消息了",name]]);

}
#pragma mark - 注册方法findEvents 并且带回调
/**
 *RCTResponseSenderBlock只接受一个参数——传递给 JavaScript 回调函数的参数数组。在上面这个例子里我们用 Node.js 的常用习惯:第一个参数是一个错误对象(没有发生错误的时候为 null),而剩下的部分是函数的返回值。
 */
RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callBack){
  callBack(@[[NSNull null],@[@"我接受到你的消息了"]]);
}
//RCT_REMAP_METHOD(findEvents, findEventsWithResolver:(RCTPromiseResolveBlock)resove rejecter:(RCTPromiseRejectBlock)reject){
//    NSArray *events = @[@"sss"];
//    if (events) {
//      resove(events);
//    } else {
//      NSError *error = [NSError new];
//      reject(@"no_events", @"There were no events", error);
//    }
//}
#pragma mark - 导出常量
/**
 *导出常量
 */
- (NSDictionary *)constantsToExport
{
  
  return @{ @"firstDayOfTheWeek": @"Monday" };
}
/**
 如果你重写了- constantsToExport,那么你还应该实现+ requiresMainQueueSetup,让React Native知道你的模块是否需要在主线程上初始化。否则你会看到一个警告,将来你的模块可能会在后台线程上初始化,除非你显式地用+ requiresMainQueueSetup退出:
 */
+ (BOOL)requiresMainQueueSetup
{
  return YES;  // only do this if your module initialization relies on calling UIKit!
}


#pragma mark - 向react-natvie 传递消息
- (NSArray *)supportedEvents
{
  return @[@"EventReminder"];
}
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
  NSString *eventName = notification.userInfo[@"name"];
  [self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
}
@end

react-native调用

import React, { Component } from 'react'
import { Text, StyleSheet, View, NativeModules,NativeEventEmitter } from 'react-native'
//JavaScript 端的代码可以创建一个包含你的模块的NativeEventEmitter实例来订阅这些事件。
const CalendarManager = NativeModules.CalendarManager
//接收来自原生app的消息
const calendarManagerEmitter = new NativeEventEmitter(CalendarManager);
const subscription = calendarManagerEmitter.addListener(
    'EventReminder',
    (reminder) => console.log("===>接收到来自原生app的消息",reminder.name)
  );
export default class CalendarView extends Component {
    state = {
        events: []
    }

    //  updateEvents = async ()=>{
    //     try {
    //       const events = await CalendarManager.findEvents();
    //       console.log('===>events',events)
    //       this.setState({ events });
    //     } catch (e) {
    //       console.error(e);
    //     }
    //   }
    componentDidMount() {
        //调用addEvent方法
        var date = new Date('2016-12-15 10:20')
        CalendarManager.addEvent(
            'Birthday Party',
            '山东',
            date.toISOString()
        )
        //调用addDic方法
        CalendarManager.addDic('生日派对',
            {
                time: date.getTime(),
                address: '山东',
                mark: '请务必光临',
            },
            (error, events) => {
                if (error) {
                    alert(error)
                } else {
                    alert(events)
                }

            }

        )
        //调用findEvents方法
        CalendarManager.findEvents((error, events) => {
            if (error) {

                console.log(error);
            } else {
                console.log('===>', events)
                this.setState({ events: events });
            }
        })
        //调用导出常量方法
        console.log('===>导出常量',CalendarManager.firstDayOfTheWeek);


        // this.updateEvents();
    }
    componentWillUnmount(){
        //取消订阅
        subscription.remove();
    }

    render() {

        return (
            
                 {JSON.stringify(this.state.events)} 
            
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center'
    },
    textStyle: {
        fontSize: 20,
    }
})


你可能感兴趣的:(react-native与原生iOS的交互)