ReactNative原生集成-iOS


目录

  • 1)搭建-原生集成rn
  • 2)demo
  • 3)访问原生侧常量
  • 4)访问原生侧方法
    • 4.1)void无返回
    • 4.2)有返回回调
  • 5)原生启动RN并获取ViewController传递的数据
  • 6)原生发送通知给RN

1)搭建-原生集成rn

  • react-native init 工程名
  • copy原iOS工程至Rn工程/ios中
  • 进入ios目录,配置CocoaPods依赖
    ~/ios/
pod init
  • 修改生成的Podfile文件
    ~/ios/Podfile
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'studyRn_Native_iOS' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for studyRn_Native_iOS

  # 'node_modules'目录一般位于根目录中
  # 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
  pod 'React', :path => '../node_modules/react-native', :subspecs => [
    'Core',
    #'CxxBridge', # 如果RN版本 >= 0.45则加入此行
    'DevSupport', # 如果RN版本 >= 0.43,则需要加入此行才能开启开发者菜单
    'RCTText',
    'RCTNetwork',
    'RCTWebSocket', # 这个模块是用于调试功能的
    # 在这里继续添加你所需要的RN模块================
  ]
  # 如果你的RN版本 >= 0.42.0,则加入下面这行
  pod "Yoga", :path => "../node_modules/react-native/ReactCommon/yoga"

   # 如果RN版本 >= 0.45则加入下面三个第三方编译依赖
  #pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  #pod 'GLog', :podspec => '../node_modules/react-native/third-party-podspecs/GLog.podspec'
  #pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

end
  • 安装pod包
    ~/ios/
pod install
pod安装完成
  • 打开studyRn_Native_iOS.xcworkspace进入xcode


    打开xcode
  • 在ViewController中导入头文件,并修改入口代码

#import "ViewController.h"
#import <React/RCTRootView.h>

@interface ViewController ()

@end

@implementation ViewController

- (IBAction)onClick:(id)sender {
    //如果这样写 需要RN侧有 index.js的入口文件
    //    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
    //如果这样写 需要RN侧有 index.ios.js的入口文件
    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://192.168.1.127:8081/index.ios.bundle"];
    RCTRootView *rootView =
    [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
                         moduleName        : @"FirstReactComponent"
                         initialProperties :
                    @{
                       @"scores" : @[
                               @{
                                   @"name" : @"Alex",
                                   @"value": @"42"
                                   },
                               @{
                                   @"name" : @"Joel",
                                   @"value": @"10"
                                   }
                               ]
                       }
                          launchOptions    : nil];
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view = rootView;
    [self presentViewController:vc animated:YES completion:nil];
}
  • 新建RN-Component
export default class FirstReactComponent extends Component {
  render() {
    const data = this.props.scores;
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          大家好,我是React界面
        </Text>
        {
            data.map(function(item,index){
                return (
                 <Text style={styles.welcome} key={index}>
                  大家好,我是{item.name},我今年{item.value}岁
                </Text>
                )
            })
        }
      </View>
    );
  }
}
  • 在RN的入口文件处注册此Component,注意:所有暴露给原生的Component都需要在入口文件处注册。
    ~/index.ios.js
import FirstReactComponent from './src/FirstReactComponent';
...
//暴露给原生使用
AppRegistry.registerComponent('FirstReactComponent', () => FirstReactComponent);
  • 打开Packager服务
    ~/工程根目录
npm start
RN集成iOS
  • 生产打release包
  //release包流程
  //第一步 新建release_ios文件夹 然后
  //react-native bundle --entry-file index.ios.js --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/
  //第二步 将assets和main.jsbundle拖进xcode [create floder references即可]
  
  //为了方便使用,也可以把打包命令写到npm script中
  //package.json中  "bundle-ios":"node node_modules/react-native/local-cli/cli.js bundle --entry-file index.ios.js  --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/"
  //运行命令直接打包 npm run bundle-ios
  
  //最后
  //    jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

2)demo

ios屏幕快照

RN屏幕快照

demo
  • 新建原生桥接模块MyNativeBridgeModule
//  MyNativeBridgeModule.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface MyNativeBridgeModule : NSObject<RCTBridgeModule>

@end
//  MyNativeBridgeModule.m
#import "MyNativeBridgeModule.h"

@implementation MyNativeBridgeModule

RCT_EXPORT_MODULE();

-(NSDictionary *)constantsToExport
{
    return @{
             @"Native_Constants_A": @"原生常量A",
             @"Native_Constants_B": @"原生常量B",
            };
}

RCT_EXPORT_METHOD(NATIVE_sendDataToNative:(NSString *)str){
    NSLog(@"收到RN侧的str数据:%@",str);
}

RCT_EXPORT_METHOD(NATIVE_sendDataToNativeCallback:(NSDictionary *)dict callback:(RCTResponseSenderBlock)callback){
    for (NSString *key in dict) {
        NSLog(@"收到RN侧的dict数据: key= %@, value= %@", key,dict[key]);
    }
    NSString *str = @"数据已收到,且被我改变啦";
    callback(@[[NSNull null],str]);
}

@end
  • RN侧文件
export default class  FirstReactComponent_Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name:'大家好,我是React界面'
    };
  }
  _sendDataToNative=()=>{
    NativeModules.MyNativeBridgeModule.NATIVE_sendDataToNative('我是来自RN的数据');
  };
  _sendDataToNativeCallback=()=>{
    const params = {
      '姓名':'杰洛特',
      '性别':'男',
    }
    NativeModules.MyNativeBridgeModule.NATIVE_sendDataToNativeCallback(
      params,
      (error,result)=>{
        this.setState({
          name:result
        })
      }
      )
  };

  render() {
    const data = this.props.scores;
    const Native_Constants_A = NativeModules.MyNativeBridgeModule.Native_Constants_A;
    return (
      <View style={styles.container}>
        {
            data.map(function(item,index){
                return (
                 <Text style={styles.welcome} key={index}>
                    我是Intent数据:{item.name},{item.value}岁
                </Text>
                )
            })
        }
        <Text style={styles.welcome}>
              {Native_Constants_A}
        </Text>
        <TouchableOpacity onPress={this._sendDataToNative} style={styles.button}>
          <Text style={styles.instructions}>
            点击发送数据给原生
          </Text>
        </TouchableOpacity>
        <Text style={styles.welcome}>
          {this.state.name}
        </Text>
       <TouchableOpacity onPress={this._sendDataToNativeCallback} style={styles.button}>
          <Text style={styles.instructions}>
            点击发送数据给原生,并回调修改
          </Text>
        </TouchableOpacity>
      </View>
    );
  }
}
//暴露给原生使用
AppRegistry.registerComponent('FirstReactComponent', () => FirstReactComponent);

3)访问原生侧常量

在MyNativeBridgeModule中

-(NSDictionary *)constantsToExport
{
    return @{
             @"Native_Constants_A": @"原生常量A",
             @"Native_Constants_B": @"原生常量B",
            };
}

RN侧只需调用即可

const Native_Constants_A = NativeModules.MyNativeBridgeModule.Native_Constants_A;

4)访问原生侧方法

  • 4.1)void无返回
RCT_EXPORT_METHOD(NATIVE_sendDataToNative:(NSString *)str){
    NSLog(@"收到RN侧的str数据:%@",str);
}
  _sendDataToNative=()=>{
    NativeModules.MyNativeBridgeModule.NATIVE_sendDataToNative('我是来自RN的数据');
  };
  • 4.2)有返回回调
RCT_EXPORT_METHOD(NATIVE_sendDataToNativeCallback:(NSDictionary *)dict callback:(RCTResponseSenderBlock)callback){
    for (NSString *key in dict) {
        NSLog(@"收到RN侧的dict数据: key= %@, value= %@", key,dict[key]);
    }
    NSString *str = @"数据已收到,且被我改变啦";
    callback(@[[NSNull null],str]);
}
  _sendDataToNativeCallback=()=>{
    const params = {
      '姓名':'杰洛特',
      '性别':'男',
    }
    NativeModules.MyNativeBridgeModule.NATIVE_sendDataToNativeCallback(
      params,
      (error,result)=>{
        this.setState({
          name:result
        })
      }
      )
  };

5)原生启动RN并获取ViewController传递的数据

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //如果这样写 需要RN侧有 index.js的入口文件
    //    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
    //如果这样写 需要RN侧有 index.ios.js的入口文件
    NSURL *jsCodeLocation = [NSURL URLWithString:@"http://192.168.1.127:8081/index.ios.bundle"];
    RCTRootView *rootView =
    [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
                         moduleName        : @"FirstReactComponent"
                         initialProperties :
     @{
       @"datas" : @[
               @{
                   @"name" : @"Alex",
                   @"value": @"42"
                   },
               @{
                   @"name" : @"Joel",
                   @"value": @"10"
                   }
               ]
       }
                       launchOptions    : nil];
    self.view = rootView;
}
const data = this.props.datas;

6)原生发送通知给RN

~ NativeBridge.h

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

//继承了RCTEventEmitter这个类,用来发送通知的
@interface NativeBridge  : RCTEventEmitter<RCTBridgeModule>

@end

~ NativeBridge.m

@implementation NativeBridge

RCT_EXPORT_MODULE();

//实现suppportEvents方法
- (NSArray<NSString *> *)supportedEvents
{
  return @[@"Native_PushTo_RN_AliPayBoardcast"];
}

//设置发送事件通知给RN侧,通知规约为 "Native_PushTo_RN_AliPayBoardcast"
- (void)AliPayBoardcastReceived:(NSNotification *)notification
{
  [self sendEventWithName:@"Native_PushTo_RN_AliPayBoardcast" body:notification.object];
}
  • 本例中实现调用支付宝支付,支付宝回调给AppDelegate
    新增单例方法,注册native本地通知,当AppDelegate接收到支付宝的回调时,发送通知给本地通知,由本地通知调用方法通知RN侧
    ~ NativeBridge.m
+ (id)allocWithZone:(NSZone *)zone {
  static NativeBridge *pushManager = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    pushManager = [super allocWithZone:zone];
    //注册通知alipay支付宝回调
    [[NSNotificationCenter defaultCenter] addObserver:pushManager selector:@selector(AliPayBoardcastReceived:) name:@"AliPayBoardcast" object:nil];
  });
  return pushManager;
}

~AppDelegate.m

// NOTE: 9.0以后使用新API接口
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
  if ([url.host isEqualToString:@"safepay"]) {
    // 支付跳转支付宝钱包进行支付,处理支付结果
    [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
      NSLog(@"result = %@",resultDic);
      [[NSNotificationCenter defaultCenter] postNotificationName:@"AliPayBoardcast" object:resultDic];
    }];
    return YES;
  }
}

参考资料

官网


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容