专栏首页BIT泽清ReactNative马甲包与iOS原生交互方式汇总,学会轻松上架App Store
原创

ReactNative马甲包与iOS原生交互方式汇总,学会轻松上架App Store

最近用RN开发SDK,涉及RN与iOS各种交互。

有些交互比如用iOS原生切换多个RN页面,以及iOS调用RN的方法,按照网上的方法调不通,一度不知如何是好,网上资料比较少。

于是自己看RN源码分析得出一些方法。 如有问题欢迎指正,有更好的思路方法欢迎分享。

一、 iOS 调用ReactNative
1,打开一个ReactNative页面
2,多个ReactNative页面切换(尽量在RN内实现)
3,iOS调用RN(分是否传参数)
二、ReactNative调用iOS
1,无参数无回调
2,有多个参数
3,有回调
4,有多个参数多个回调

说明:

1,Demo: RNInteractionWithIOS

2,ReactNative版本:

"react": "16.4.1",
"react-native": "0.56.0"

一、 iOS 调用ReactNative

1,打开一个ReactNative页面

比如react-native init RNInteractionWithiOS 创建一个应用之后就会自动在 RNInteractionWithiOS->ios->RNInteractionWithiOS->AppDelegate.m中生成打开一个ReactNative页面的代码。核心代码如下:

 NSURL *jsCodeLocation;
 
 jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
 
 RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                     moduleName:@"RNInteractionWithiOS"
                                              initialProperties:nil
                                                  launchOptions:launchOptions];
 rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
 
 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
 UIViewController *rootViewController = [UIViewController new];
 rootViewController.view = rootView;
 self.window.rootViewController = rootViewController;
 [self.window makeKeyAndVisible];

2,多个ReactNative页面切换(尽量在RN内实现)

这个有点难度,当时还研究了半天,几乎没有资料可参考

  • RN核心代码: 在index.js中
AppRegistry.registerComponent("App", () => App);
AppRegistry.registerComponent("App2", () => App2);

iOS中OC核心代码:

  • 设置RCTBridge的代理
  • 实现代理方法- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge;
  • 最关键的:通常情况下我们会使用initWithBundleURL创建一个RCTRootView,此处必须使用initWithBridge创建RCTRootView
#import "ViewController.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
 
@interface ViewController ()<RCTBridgeDelegate>
@property (nonatomic, strong) RCTBridge *bridge;
 
@end
 
@implementation ViewController
 
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
  return [NSURL URLWithString:@"http://127.0.0.1:8081/index.bundle?platform=ios"];// 模拟器
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
  _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
}
 
#define RNBounds CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width-50, UIScreen.mainScreen.bounds.size.height/2.f)
 
- (IBAction)openRNOne {
  [self removeRNPage];
  [self loadRNView:@"App"];
}
 
- (IBAction)openRNTwo {
  [self removeRNPage];
  [self loadRNView:@"App2"];
}
 
- (IBAction)removeRNPage {
  [self.view.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if ([obj isKindOfClass:[RCTRootView class]]) {
      [obj removeFromSuperview];
      return;
    }
  }];
}
 
- (void)loadRNView:(NSString *)moduleName {
  RCTRootView *rnView2 = [[RCTRootView alloc] initWithBridge:_bridge
                                                  moduleName:moduleName
                                           initialProperties:nil];
  rnView2.bounds = RNBounds;
  rnView2.center = self.view.center;
  [self.view addSubview:rnView2];
}

3,iOS调用RN(分是否传参数)

  • RN核心代码
  componentWillMount() {
      DeviceEventEmitter.addListener('EventInit', (msg) => {
          let receive = "EventInit: " + msg;
          console.log(receive);
          this.setState({notice: receive});
      });
 
      DeviceEventEmitter.addListener('EventLogin', (msg) => {
          let receive = "EventLogin: " + msg;
          console.log(receive);
          this.setState({notice: receive});
      });
  }
  • iOS核心代码:
    • 创建的iOS交互类要引用#import<React/RCTBridgeModule.h>#import <React/RCTEventEmitter.h>,继承RCTEventEmitter,并遵守RCTBridgeModule
    • 很关键的:交互类要设置bridge当前RCTRootView的bridge[[ReactInteraction shareInstance] setValue:rnView.bridge forKey:@"bridge"];

ReactInteraction.h文件

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
 
@interface ReactInteraction : RCTEventEmitter <RCTBridgeModule>
+ (instancetype)shareInstance;
- (void)init:(NSString *)parameter;
- (void)login;
@end

ReactInteraction.m文件

#import "ReactInteraction.h"
 
#define INIT @"EventInit"
#define LOGIN @"EventLogin"
 
@implementation ReactInteraction
static ReactInteraction *instance = nil;
 
RCT_EXPORT_MODULE();
+ (instancetype)shareInstance {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    instance = [[self alloc] init];
  });
  return instance;
}
 
- (NSArray<NSString *> *)supportedEvents
{
  return @[INIT,LOGIN];
}
 
RCT_EXPORT_METHOD(init:(NSString *)msg) {
  [self.bridge enqueueJSCall:@"RCTDeviceEventEmitter"
                      method:@"emit"
                        args:@[INIT, msg]
                  completion:NULL];
}
 
RCT_EXPORT_METHOD(login) {
  [self.bridge enqueueJSCall:@"RCTDeviceEventEmitter"
                      method:@"emit"
                        args:@[LOGIN]
                  completion:NULL];
}
 
@end

二、ReactNative调用iOS

  • RN核心代码:
import {NativeModules} from 'react-native';
const NativeInteraction = NativeModules.NativeInteraction;

OS核心代码:

  • 注意点1:RCT_EXPORT_METHODRCT_REMAP_METHOD宏定义的使用区别(个人总结,有不对请指正)
  • RCT_EXPORT_METHOD:用于仅有一个参数或回调
  • RCT_REMAP_METHOD:用于有多个参数或(和)多个回调
  • (了解更多可以看RN宏定义源码1,下面👇贴出关键两句)
  • 注意点2:iOS回调方式有两种
  • callback(@[jsonString]); ((RCTPromiseResolveBlock)resolver)
  • Promise方式:_resolveBlock(@[jsonString]); ((RCTResponseSenderBlock)callback) (了解更多看RN源码2

源码1:

#define RCT_REMAP_METHOD(js_name, method) \
  _RCT_EXTERN_REMAP_METHOD(js_name, method, NO) \
  - (void)method RCT_DYNAMIC;
 
#define RCT_EXPORT_METHOD(method) \
  RCT_REMAP_METHOD(, method) 

源码2:

typedef void (^RCTResponseSenderBlock)(NSArray *response);
typedef void (^RCTResponseErrorBlock)(NSError *error);
typedef void (^RCTPromiseResolveBlock)(id result);
typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);

1,无参数回调

RN核心代码:

    NativeInteraction.RNTransferIOS();

iOS核心代码:

RCT_EXPORT_METHOD(RNTransferIOS) {
  NSLog(@"RN调用iOS");
}

2,有多个参数

RN核心代码:

RCT_EXPORT_METHOD(RNTransferIOSWithParameter:(NSString *)logString) {
  NSLog(@"来自RN的数据:%@",logString);
}

3,有回调

RN核心代码:

    NativeInteraction.RNTransferIOSWithCallBack((data) => {
      this.setState({notice: data});
    });

iOS核心代码:

RCT_EXPORT_METHOD(RNTransferIOSWithCallBack:(RCTResponseSenderBlock)callback) {
  callback(@[[NSString stringWithFormat:@"来自iOS Native的数据:%@",TestNativeJsonData]]);
}

4,有多个参数多个回调

  • RN核心代码:
NativeInteraction.RNTransferIOSWithParameterAndCallBack('rndata1','rndata2').then(result =>{       let jsonString = JSON.stringify(result);       this.setState({notice: jsonString});     }).catch(error=>{     });
iOS核心代码:{   RCTPromiseResolveBlock _resolveBlock;   RCTPromiseRejectBlock _rejectBlock; } RCT_REMAP_METHOD(RNTransferIOSWithParameterAndCallBack, para1:(NSString *)para1 para2:(NSString *)para2 resolver:(RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)reject) {   NSLog(@"来自RN的数据:para1——%@, para2——%@",para1, para2);     _resolveBlock=resolver;   _rejectBlock=reject;   NSString *jsonString = TestNativeJsonData;   _resolveBlock(@[jsonString]); } 如上有问题欢迎各路大神留言指正,写博客不容易,大家相互学习。Q.⒉⒉O.⒌⒊⒌⒎O.O.7可提供金融资质Ios开发者账号代上架5.2.1或4.3被拒的应用!公司没有资质的现金贷小额金融贷款超市,借贷类、p2p、理财金融类的iOS上架

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • React Native应用部署/马甲包热更新-CodePush最新集成总结(2018年最新)

    React Native支持大家用React Native技术开发APP,并打包生成一个APP。在动态更新方面React Native只是提供了动态更新的基础,...

    jiang chen
  • 【iOS 开发】教你利用企业级开发者把你无法上架到App Store的北京赛车app

    【iOS 开发】教你利用企业级开发者把你无法上架到App Store的北京赛车app

    jiang chen
  • app 安全和ios及安卓马甲包代码混淆的demo的手把手教你的详细教程

    App Security And CodeConfuse (app 安全和代码混淆的demo的手把手教你的详细教程)

    jiang chen
  • 我理解的“大前端”或“大无线”

    本文主要是介绍作者所在团队最近的一些变化和思考,包括前言、NodeJS职能变化、ReactNative的大规模应用、专门的架构组职能、总结五部分。

    疯狂的技术宅
  • Python 输入时间字符串以分钟单位计算时间差

    之前转载过一篇使用python dateTime模块处理时间差的文章,文章中讲解了如何按照days,hours和seconds单位来计算时间差。这里讲解一下如何...

    我是李超人
  • JanusGraph实战笔记·数据写入·查询

    JanusGraph·How to represent, write or query an array in JanusGraph?

    陈黎栋
  • 【动画】当我们在读写Socket时,我们究竟在读写什么?

    套接字socket是大多数程序员都非常熟悉的概念,它是计算机网络编程的基础,TCP/UDP收发消息都靠它。我们熟悉的web服务器底层依赖它,我们用到的MySQL...

    Java后端技术
  • 【动画】当我们在读写Socket时,我们究竟在读写什么?

    套接字socket是大多数程序员都非常熟悉的概念,它是计算机网络编程的基础,TCP/UDP收发消息都靠它。我们熟悉的web服务器底层依赖它,我们用到的MySQL...

    老钱
  • 图解 | 当我们在读写 Socket 时,我们究竟在读写什么?

    套接字socket是大多数程序员都非常熟悉的概念,它是计算机网络编程的基础,TCP/UDP收发消息都靠它。我们熟悉的web服务器底层依赖它,我们用到的MySQL...

    芋道源码
  • C++多线程-无锁链表

    前面,为了使得写操作快速进行,我们定义了顺序锁。但是顺序锁有个缺点,那就是处理的数据不能是指针,否则可能会导致exception。那么有没有办法使得处理的数据包...

    cwl_java

扫码关注云+社区

领取腾讯云代金券