详解React Native与IOS端之间的交互

前置准备

首先最好了解一点关于 oc 的语法知识

1.创建声明文件nativeModule.h

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>

@interface nativeModule : NSObject <RCTBridgeModule>

@end

2.创建文件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 差不多

方法 4 获取 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/learn-rn

关于原生端和 RN 端的交互基本就是这些了,当然原生端还有更多,更复杂的操作,比如进程什么的,如果想写桥接方法,这个也会碰到很多,不过掌握了上面这些,对于一些三方 SDK 的调用是够用了

以上就是详解React Native与IOS端之间的交互的详细内容,更多关于React Native与IOS端之间的交互的资料请关注我们其它相关文章!

(0)

相关推荐

  • IOS React等Title不显示问题解决办法

    IOS React等Title不显示问题解决办法 单页应用里整个页面只会在第一次完全刷新,后面只会局部刷新(一般不包括head及里面的title),所以无法在服务器端控制title,只能在页面刷新的时候通过js修改title.常规做法如下,可惜在iOS微信浏览器无效. 问题原因: 因为微信浏览器首次加载页面初始化title后,就再也不监听 document.title的change事件. 解决方案: 修改title之后,给页面加上一个内容为空的iframe,随后立即删除这个iframe,这时候会

  • react-native组件中NavigatorIOS和ListView结合使用的方法

    前言 本文主要给大家介绍了关于react-native组件中NavigatorIOS和ListView结合使用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 先看效果 使用方法 index.ios.js import React, {Component} from 'react'; import { AppRegistry, NavigatorIOS } from 'react-native'; import NewsList from './components/

  • React Native第三方平台分享的实例(Android,IOS双平台)

    本文主要介绍了React Native第三方平台分享的实例(Android,IOS双平台),分享给大家,具体如下: 源码已开源到Github,地址请点击:react-native-share[一行代码,双平台分享] 目前支持分享的平台有[QQ][QQ空间][微信][朋友圈][微博][FaceBook]  欢迎大家star,fork..... [ Android平台配置 ] 1. app目录下创建 libs 文件夹,添加依赖文件[直接复制源码中 libs 目录即可] 2. app / src /

  • Reactnative-iOS回调Javascript的方法

    Reactnative可以调用原生模块,原生模块也可以给JavaScript发送事件通知.最好的方法是继承RCTEventEmitter.自定义继承自PushEventEmitter的子类RCTEventEmitter. #import <Foundation/Foundation.h> #import <React/RCTBridgeModule.h> #import <React/RCTEventEmitter.h> @interface PushEventEmit

  • IOS React Native FlexBox详解及实例

    IOS React Native FlexBox详解及资料整理, # 前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所偏差,在学习中如果有错会及时修改内容,也欢迎万能的朋友们批评指出,谢谢 文章第一版出自简书,如果出现图片或页面显示问题,烦请转至 简书 查看 也希望喜欢的朋友可以点赞,谢谢 什么是 FlexBox 布局 在 html 中,界面的搭建都是采用 C

  • ios原生和react-native各种交互的示例代码

    需求:让一个表格视图中的cell能左滑删除,效果图如下: 目前RN中的ListView主要问题是复用,以及其他一些细节如索引视图.左滑删除.编辑等,要想在RN上自定义实现原生的这种效果尚有一定的问题,在必要时可以考虑使用原生的UITableView,数据从RN端传递 1.原生端编写表格控制器NativeTableViewController,暴露的属性如下 datas为表格数据源,另外一个为需要暴露给RN调用用方法. 2.框架只提供了暴露UIView给RN端的接口,所以需要制作一个中转UIVie

  • react axios 跨域访问一个或多个域名问题

    1.react + axios 跨域访问一个域名 配置非常简单,只需要在当前的 package.json 文件里面配置: "proxy":"http://iot-demo-web-dev.autel.com", //当然,这里是一个假地址 像这样: 这样跨域便完成了,当然,也可以像网上那样,多几段代码,像这样: 我不知道你们写入这段代码会怎么样,反正我是会报错,具体报错是怎么我这里没办法展示,因为我的项目已经 运行了 npm run eject 这个命令 报错的意思

  • React-Native Android 与 IOS App使用一份代码实现方法

    React-Native  Android 与 IOS 共用代码 React-Native 开发的App, 所有组件iOS & Android 共用, 共享一份代码 包括一些自定义的组件, 如NavigationBar, TabBar, SegmentedControl, 使用字体图标, 具有一定的参考意义 主要专注于布局, 共享组件/代码, 以及一些React自带的组件, 如: ScrollView, TouchableOpacity, View, Text, ListView, Image,

  • iOS端React Native差异化增量更新的实现方法

    前言 作为一名iOS原生开发工程师,通过一个礼拜的面试之后发现,原来并不想学的react-native真的是火的一塌糊涂,坐标:杭州,很多公司招聘iOS开发除了原来的OC和Swift,多了一门新语言:react-native,真的是要人老命啊,Swift4.0刚刚看完,又得花时间学RN.入职之后也开始学react-native,算是小白一枚,下面是我的个人总结,有大神看出错误,请不要打我或者骂我,联系我邮箱dadadoubi@qq.com. RN具有的优势有很多,跨平台开发,一套代码Androi

  • 详解React Native与IOS端之间的交互

    前置准备 首先最好了解一点关于 oc 的语法知识 1.创建声明文件nativeModule.h #import <Foundation/Foundation.h> #import <React/RCTBridgeModule.h> @interface nativeModule : NSObject <RCTBridgeModule> @end 2.创建文件nativeModule.m #import <Foundation/Foundation.h> #i

  • 详解React Native项目中启用Hermes引擎

    目录 引言 一.启用 Hermes 引擎 1.1 Android 1.2 iOS 二.Hermes 引擎使用 2.1 检查 Hermes 引擎是否启用 2.2 绑定Hermes 2.3 使用DevTools在Hermes上调试JS 引言 目前,最新版本的React Native(0.70.0及以上版本)已经默认开启了Hermes引擎.而Hermes则是专门针对React Native应用而优化的全新JavaScript引擎,启用Hermes引擎可以优化启动时间,减少内存占用以及空间占用. 一.启

  • 详解React Native监听Android回退按键与程序化退出应用

    详解React Native监听Android回退按键与程序化退出应用 前言 我们知道Android回退按键,会控制页面返回, 并且退出应用并非真正意义退出,仍在后台运行,所以在某些场景下需要监控android回退按键,那么在React Native中应该如何应用呢?我们具体来看看. BackAndroid 此模块用于监听硬件的back键操作. 看下具体代码: BackAndroid.addEventListener('hardwareBackPress', function() { if (!

  • 详解React Native中如何使用自定义的引用路径

    目录 RN的相对路径地狱 RN的自定义路径需要的依赖 解决自定义引用路径导致的eslint报错问题 RN的相对路径地狱 我刚接触RN时,就发现所有的demo中给出来的路径都是相对路径,我自己的练习项目中想改成自定义的绝对路径,但是发现并没有我做前端时熟悉的webpack.config.js,所以也就不知道该怎么改了.伴随着RN的学习和开发练习,我的代码也变得越来越多,越来越复杂,我逐渐发现RN的相对路径越来越麻烦,比如我把某个文件移动到另一个不同深度的文件夹中,那么就需要把所有引用这个文件的地方

  • 详解React项目的服务端渲染改造(koa2+webpack3.11)

    因为对网页SEO的需要,要把之前的React项目改造为服务端渲染,经过一番调查和研究,查阅了大量互联网资料.成功踩坑. 选型思路:实现服务端渲染,想用React最新的版本,并且不对现有的写法做大的改动,如果一开始就打算服务端渲染,建议直接用NEXT框架来写 项目地址:https://github.com/wlx200510/react_koa_ssr 脚手架选型:webpack3.11.0 + react Router4 + Redux + koa2 + React16 + Node8.x 主要

  • 详解react、redux、react-redux之间的关系

    本文介绍了react.redux.react-redux之间的关系,分享给大家,也给自己留个笔记,具体如下: React 一些小型项目,只使用 React 完全够用了,数据管理使用props.state即可,那什么时候需要引入Redux呢? 当渲染一个组件的数据是通过props从父组件中获取时,通常情况下是 A --> B,但随着业务复杂度的增加,有可能是这样的:A --> B --> C --> D --> E,E需要的数据需要从A那里通过props传递过来,以及对应的 E

  • 详解React Native开源时间日期选择器组件(react-native-datetime)

    项目介绍 该组件进行封装一个时间日期选择器,同时适配Android.iOS双平台,该组件基于@remobile/react-native-datetime-picker进行开发而来 配置安装 npm install react-native-datetime --save 1.1.iOS环境配置 上面步骤完成之后,直接前台写js代码即可 1.2.Android环境配置 在android/setting.gradle文件中如下配置 ... include ':react-native-dateti

  • 详解React Native 屏幕适配(炒鸡简单的方法)

    前言 React Native 可以开发 ios 和 android 的 app,在开发过程中,势必会遇上屏幕适配(ios 好几种尺寸的屏幕以及 android 各种尺寸的屏幕)的问题,下面介绍一种几行代码搞定 RN 适配的方法! 屏幕适配的前置知识 RN 中的尺寸单位为 dp,而设计稿中的单位为 px 原理 虽然单位不同,但是元素所占屏幕宽度的比例是相同的 利用元素所占屏幕比例不变的特性,来将 px 转为 dp(这样实现屏幕适配的话,在不同尺寸的屏幕下,元素会等比放大或缩小) 公式如下: 设计

  • 详解React native fetch遇到的坑

    最近在自学react native,学习过程中遇到了不少的坑,下面将针对登录这一功能来详细介绍一下以下遇到的两个问题. 1.在请求数据的时候,一般情况下我们会直接提交Content-type是json数据格式的请求.类似 fetch('https://mywebsite.com/endpoint/', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', },

  • 详解React Native顶|底部导航使用小技巧

    导航一直是App开发中比较重要的一个组件,ReactNative提供了两种导航组件供我们使用,分别是:NavigatorIOS和Navigator,但是前者只能用于iOS平台,后者在ReactNative0.44版本以后已经被移除了. 好在有人提供了更好的导航组件,就是我们今天要讲的react-navigation,并且ReactNative官方更推荐我们使用此组件. 本篇文章只讲解基础用法,如果你想了解更多,请戳这里->戳我.  简介 react-navigation主要包括导航,底部tab,

随机推荐