react native学习笔记26——iOS原生模块的封装与调用

1.前言

上一篇文章介绍封装Android原生模块,今天将介绍如何封装ios原生模块供React native调用。在React Native中,ios平台原生模块是一个实现了RCTBridgeModule协议的Objective-C类,其中RCT是ReaCT的缩写。这里会涉及到一些Objective-C的代码编写,不过不用担心,有一定的ios开发的基础当然更好,如果你之前从未接触使用过Objective-C,可能有些语法理解起来较为困难,但这并不妨碍阅读,本文用编程世界里最经典的HelloWorld实例来介绍ios原生模块的封装。但如果以后想封装更为复杂的ios原生平台模块,掌握Objective-C或者Swift的语法还是必须的。

2.创建模块类

..\ExerciseProject\ios\ExerciseProject目录下新建HelloWorld.h和HelloWorl.m文件,或使用Xcode打开..\ExerciseProject\ios\ExerciseProject.xcodeproj文件,新建HelloWorld类,会自动生成HelloWorld.h和HelloWorl.m文件。.h头文件包含了类的接口,.m文件中实现了具体的功能。首先看HelloWorld.h:

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

这里导入了RCTBridgeModule.h头文件,RCTBridgeModule是React Native提供的与iOS原生通信的桥接实现。接着定义了HelloWorld类继承于NSObject并实现了RCTBridgeModule接口。

再来看HelloWorld.m:

#import "HelloWorld.h"
#import "RCTLog.h"

@implementation HelloWorld

RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(hello:(NSString *)name)
{
  RCTLogInfo(@"Hello %@ from IOS", name);
}
@end

第一行导入了相应的.h文件,由于后面需要使用RCTLogInfo输出日志到应用台,这里导入了RCTLog.h。@implementation与@end之间是HelloWorld的具体实现。通过RCT_EXPORT_MODULE()宏导出此原生模块供React Native接口调用,而RCT_EXPORT_METHOD()宏来实现要给Javascript使用的方法。

3.在javascript端使用

为了使当前封装的模块在JavaScript中可以方便使用,通常会把该原生模块封装成JavaScript模块。这样可以省下每次访问组件都要加入NativeModules的步骤,不过该步骤不是必须的。
本例中在\ExerciseProject\src\12_nativeapi\中新建一个HelloWorldIOS.js文件

let { NativeModules } = require('react-native');
module.exports = NativeModules.HelloWorld;

然后在别的JavaScript文件代码中就可以如下进行访问:

import HelloWorldIOS from './HelloWorldIOS';
...
HelloWorldIOS.hello('Jack');

具体在JavaScript文件中的调用方法实例代码如下:

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
} from 'react-native';

import HelloWorldIOS from './HelloWorldIOS';

export default class HelloWorldIOSDemo extends Component {
    onPress(){
        HelloWorldIOS.hello('Jack');
    }
    render() {
        return (
            <View style={{marginTop:40}}>
                <Button onPress={this.onPress.bind(this)} title="Hello" />
            </View>
        );
    }
}

4.参数类型说明

上面例子中我们传入了string类型的参数,实际应用中还可能需要各种类型的参数。RCT_EXPORT_METHOD 支持所有标准JSON类型。具体如下:

  • string (NSString)
  • number (NSInteger, float, double, CGFloat, NSNumber)
  • boolean (BOOL, NSNumber)
  • array (NSArray) 包含本列表中任意类型
  • object (NSDictionary) 包含string类型的键和本列表中任意类型的值
  • function (RCTResponseSenderBlock)

除此以外,任何RCTConvert类支持的类型也都可以使用。RCTConvert是React Native提供的一个类型转换库。例如在上面提到的支持的类型中没有时间类型,如果我们需要传递时间即可通过RCTConvert进行类型转换。

RCTConvert的使用具体可见下例:
步骤如前面2、3小节,先创建DateIOS.h

#import <React/RCTBridgeModule.h>
#import <React/RCTConvert.h>
@interface DateIOS : NSObject<RCTBridgeModule>

@end

再创建DateIOS.m

#import "DateIOS.h"
@implementation DateIOS
RCT_EXPORT_MODULE();
RCT_REMAP_METHOD(compareDate, date1:(nonnull NSNumber *)d1 date2:(nonnull NSNumber *)d2)
{
  NSDate* dt1 = [RCTConvert NSDate:d1];
  NSDate* dt2 = [RCTConvert NSDate:d2];
  NSComparisonResult result = [dt1 compare:dt2];
  switch(result){
    case NSOrderedAscending:
    {
       NSLog(@"compare result %@",@"start time < end time");
    }
    case NSOrderedDescending:
    {
      NSLog(@"compare result %@",@"start time > end time");
    }
  }

}
@end

在javascript端使用

import React, { Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    Button,
    DatePickerIOS,
    NativeModules
} from 'react-native';

export default class DateIOSDemo extends Component {
    constructor(){
      super();
      this.state = {startDate: new Date(), endDate: new Date()};
    }

    onPressDateCompare() {
          let dateCompare = NativeModules.DateIOS;
          dateCompare.printDate(this.state.startDate.getTime(), this.state.endDate.getTime());
    }
    onStartDateChange(date) {
          this.setState({startDate: date});
    }
    onEndDateChange(date) {
          this.setState({endDate: date});
    }
    render() {
            return (
              <View>
                <DatePickerIOS
                  date={this.state.startDate}
                  mode='date'
                  onDateChange={this.onStartDateChange.bind(this)} />
                <DatePickerIOS
                  date={this.state.endDate}
                  mode='date'
                  onDateChange={this.onEndDateChange.bind(this)} />
                <Button onPress={this.onPressDateCompare.bind(this)} title="Compare Date" />
              </View>
            );
    }
}

上例中由于不能在桥接通道里传递Date对象,所以需要把日期转化成字符串或数字来传递。在ios端通过如下方式进行转换:

NSDate* dt1 = [RCTConvert NSDate:d1];

在javascript端将日期以unix时间戳形式传递:

  let dateCompare = NativeModules.DateIOS;
  dateCompare.printDate(this.state.startDate.getTime(), this.state.endDate.getTime());

也可以以ISO-8601的字符串形式传递:

  let dateCompare = NativeModules.DateIOS;
  dateCompare.printDate(this.state.startDate.toISOString(), this.state.endDate.toISOString());

这两种方式都会被转换为正确的NSDate类型。但如果提供一个不合法的值,例如一个Array,则程序会报错。

以上是关于iOS原生模块的封装与调用的一个简单介绍。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Native封装原生第三方SDK的步骤如下: 1. 创建一个原生模块Native Module),以便React Native应用程序可以与原生代码进行交互。对于iOS,你需要创建一个Objective-C或Swift类;对于Android,你需要创建一个Java类。 2. 在原生模块中编写代码,调用第三方SDK的API并将其封装为JavaScript可以调用的函数。你可以使用React Native提供的RCT_EXPORT_MODULE宏将该模块导出到JavaScript中。例如,下面是一个在iOS封装Facebook SDK的例子: ```objective-c #import <FBSDKCoreKit/FBSDKCoreKit.h> #import <React/RCTBridgeModule.h> @interface MyFacebookModule : NSObject <RCTBridgeModule> @end @implementation MyFacebookModule RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(login:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init]; [loginManager logInWithPermissions:@[@"public_profile", @"email"] fromViewController:nil handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) { if (error) { reject(@"login_error", error.localizedDescription, error); } else if (result.isCancelled) { reject(@"login_cancelled", @"User cancelled login", nil); } else { resolve(result.token.tokenString); } }]; } @end ``` 这个模块导出了一个名为`login`的函数,该函数会登录Facebook,并返回一个Promise,该Promise将在登录成功后解析为一个Facebook访问令牌,或在登录失败时拒绝。 3. 在JavaScript中导入原生模块,并使用它提供的函数。例如,你可以使用以下代码在React Native应用程序中调用上述iOS模块: ```javascript import { NativeModules } from 'react-native'; const { MyFacebookModule } = NativeModules; MyFacebookModule.login() .then(token => console.log(`Facebook access token: ${token}`)) .catch(error => console.error(`Failed to login: ${error}`)); ``` 这个代码导入了名为`MyFacebookModule`的原生模块,并调用其`login`函数。当该函数返回时,它会返回一个Promise,你可以使用该Promise来处理成功或失败的情况。 通过将原生第三方SDK封装React Native模块中,你可以轻松地在React Native应用程序中使用该SDK,并将其与JavaScript代码无缝集成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值