ReactNative: 将自定义的ReactNative组件制作成第三方库的详细流程(制作-->发布)

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

ReactNative: 将自定义的ReactNative组件制作成第三方库的详细流程(制作-->发布)

XYQ全哥   2020-01-18 我要评论

一、简介

在讲本篇博文之前,需要你熟知怎么自定义ReactNative组件,然后才好学习将自定义的ReactNative组件制作成第三方库。本文中的自定义的ReactNative组件LoginManager API 源自上篇文章,所以需要先看一下上篇博文。言归正传,ReactNative的确提供了一个非常便捷的方式来扩展Native模块。如果要把模块做成第三方组件的话,还有一些工作要做:首先以一个静态库工程来编译模块代码,提供JavaScript的封装,最后创建Package.json来支持node的引用。在步骤开始之前,我先把上篇文章中创建Native原生模块的LoginManager API组件的类贴出来,如下所示:

LoginManager.h

//
//  LoginManager.h
//  RNDemo
//
//  Created by 夏远全 on 2020/1/16.
//  Copyright © 2020 Facebook. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <React/RCTUtils.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTBridgeModule.h>

NS_ASSUME_NONNULL_BEGIN

//OC中定义一个枚举并导出
typedef NS_ENUM(NSInteger, MoveDiretion){
    MoveDiretionNone,
    MoveDiretionLeft,
    MoveDiretionRight,
    MoveDiretionBottom,
    MoveDiretionTop
};

@interface LoginManager : NSObject<RCTBridgeModule>

@end

NS_ASSUME_NONNULL_END
View Code

LoginManager.m

//
//  LoginManager.m
//  RNDemo
//
//  Created by 夏远全 on 2020/1/16.
//  Copyright © 2020 Facebook. All rights reserved.
//

#import "LoginManager.h"

#ifdef DEBUG
#define NSLog(format, ...) printf("[%s] %s [第%d行] %s\n", __TIME__, __FUNCTION__, __LINE__, [[NSString stringWithFormat:format, ## __VA_ARGS__] UTF8String]);
#else
#define NSLog(format, ...)
#endif

@implementation LoginManager

//初始化, 添加屏幕旋转监听者
-(instancetype)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
    }
    return self;
}

//导出模块类
RCT_EXPORT_MODULE();


//重映射,auth为code方法的新名称
RCT_REMAP_METHOD(auth,code:(NSString *)account{
                      NSLog(@"%s---获取验证----",__func__);
                      NSLog(@"account----%@",account);
                  });

//login为方法名
RCT_EXPORT_METHOD(login:(NSString *)account password:(NSString *)password{
                      NSLog(@"%s---登录账号----",__func__);
                      NSLog(@"account----%@",account);
                      NSLog(@"password----%@",password);
                  });

//logout为方法名
RCT_EXPORT_METHOD(logout:(NSString *)account{
                      NSLog(@"%s---退出账号----",__func__);
                      NSLog(@"account----%@",account);
                  });

//设置普通的回调函数
//fetchUserInfoWithToken为方法名,successCallback为成功回调,failureCallback为失败回调
RCT_EXPORT_METHOD(fetchUserInfoWithToken:(NSString *)token success:(RCTResponseSenderBlock)successCallback failure:(RCTResponseErrorBlock)failureCallback
    {
            if(token.length>0 && successCallback){
                  successCallback(@[
                                    @"account = xiayuanquan",
                                    @"password = 123456",
                                    [NSString stringWithFormat:@"token = %@",token]
                                  ]);
            }
            else{
                  if(failureCallback){
                        failureCallback(
                                          [[NSError alloc] initWithDomain:NSOSStatusErrorDomain
                                                                     code:404
                                                                 userInfo: @{NSLocalizedDescriptionKey: @"token exception"}]
                                        );
                  }
            }
    });


//设置异步处理的回调函数
//sendMessage为方法名,successCallback为成功回调,failureCallback为失败回调
RCT_EXPORT_METHOD(sendMessage:(NSString *)message success:(RCTPromiseResolveBlock)successCallback failure:(RCTPromiseRejectBlock)failureCallback
    {
            if(message.length>0 && successCallback){
                  successCallback(@"发送成功!");
            }
            else{
                  if(failureCallback){
                      failureCallback(@"300",@"发送失败",nil);
                  }
            }
    });


//重写constantsToExport, 枚举常量导出
- (NSDictionary<NSString *, id> *)constantsToExport {
   return @{
        @"MoveDiretionNone": @(MoveDiretionNone),
        @"MoveDiretionLeft": @(MoveDiretionLeft),
        @"MoveDiretionRight": @(MoveDiretionRight),
        @"MoveDiretionBottom": @(MoveDiretionBottom),
        @"MoveDiretionTop": @(MoveDiretionTop)
   };
}

//定义一个移动方法,根据传入的枚举值移动
//move为方法名
RCT_EXPORT_METHOD(move:(MoveDiretion)moveDiretion{
                    switch(moveDiretion){
                        case MoveDiretionNone:
                             NSLog(@"仍保持原始位置 --- MoveDiretionNome");
                        break;
                        case MoveDiretionLeft:
                             NSLog(@"向左边移动位置 --- MoveDiretionLeft");
                        break;
                        case MoveDiretionRight:
                             NSLog(@"向右边移动位置 --- MoveDiretionRight");
                        break;
                        case MoveDiretionBottom:
                             NSLog(@"向下边移动位置 --- MoveDiretionBottom");
                        break;
                        case MoveDiretionTop:
                             NSLog(@"向上边移动位置 --- MoveDiretionTop");
                        break;
                    }
                 });


//可以重写队列,给当前模块类指定自定义的串行队列。若不指定,则系统默认会给当前模块类随机分配一个串行队列。
//这个方法一旦重写。当前模块的所有方法均会在该自定义的串行队列中异步执行
-(dispatch_queue_t)methodQueue{
    return dispatch_queue_create("com.facebook.ReactNative.LoginManagerQueue", DISPATCH_QUEUE_SERIAL);
}

//定义一个方法,获取线程和队列信息
//thread为方法名
RCT_EXPORT_METHOD(thread:(BOOL)newQueue{
                  
              const char *queueName = dispatch_queue_get_label([self methodQueue]);
              NSLog(@"当前线程1 ------- %@-----%s", [NSThread currentThread], queueName);
              
              if(newQueue){
                  
                  dispatch_async(dispatch_get_main_queue(), ^{
                      const char *queueName2 = dispatch_queue_get_label(dispatch_get_main_queue());
                      NSLog(@"当前线程2 ------- %@ -------%s", [NSThread currentThread], queueName2);
                  });
          
                  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                      const char *queueName3 = dispatch_queue_get_label(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
                      NSLog(@"当前线程3 ------- %@-------%s", [NSThread currentThread], queueName3);
                  });
              }
          });


//获取当前屏幕的尺寸
static NSDictionary *Dimensions(){
    CGFloat width = MIN(RCTScreenSize().width, RCTScreenSize().height);
    CGFloat height = MAX(RCTScreenSize().width, RCTScreenSize().height);
    CGFloat scale = RCTScreenScale();
    if(UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)){
        width = MAX(RCTScreenSize().width, RCTScreenSize().height);
        height = MIN(RCTScreenSize().width, RCTScreenSize().height);
    }
    return @{
        @"width": @(width),
        @"height": @(height),
        @"scale": @(scale)
    };
}
//定义一个方法,获取屏幕信息
//getDimensions为方法名
RCT_EXPORT_METHOD(getDimensions:(RCTResponseSenderBlock)callback{
    if (callback) {
        callback(@[[NSNull null], Dimensions()]);
    }
});

//监听方法,使用RCTEventDispatcher的eventDispatcher调用sendDeviceEventWithName函数发送事件信息
//可以将事件名称作为常量导出,提供给ReactNative中使用,也即添加到constantsToExport方法中的字典中即可。类似上面的枚举。
@synthesize bridge = _bridge;
-(void)orientationDidChange:(NSNotification *)notification {
  [_bridge.eventDispatcher sendDeviceEventWithName:@"orientationDidChange" body:@{
      @"orientation": UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation) ? @"Landscape": @"Portrait",
      @"Dimensions": Dimensions()}
   ];
}

//移除监听者
-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end
View Code

RCTConvert+MoveDiretion.h

//
//  RCTConvert+MoveDiretion.h
//  RNDemo
//
//  Created by 夏远全 on 2020/1/17.
//  Copyright © 2020 Facebook. All rights reserved.
//

#import <React/RCTConvert.h>

NS_ASSUME_NONNULL_BEGIN

@interface RCTConvert (MoveDiretion)

@end

NS_ASSUME_NONNULL_END
View Code

RCTConvert+MoveDiretion.m

//
//  RCTConvert+MoveDiretion.m
//  RNDemo
//
//  Created by 夏远全 on 2020/1/17.
//  Copyright © 2020 Facebook. All rights reserved.
//

#import "RCTConvert+MoveDiretion.h"
#import "LoginManager.h"

@implementation RCTConvert (MoveDiretion)

//给RCTConvert类添加扩展,这样在模块方法调用中使用常量导出的枚举值,通信到Native中时,会从整型自动转换为定义的枚举类型
RCT_ENUM_CONVERTER(MoveDiretion,(@{
   @"MoveDiretionNone": @(MoveDiretionNone),
   @"MoveDiretionLeft": @(MoveDiretionLeft),
   @"MoveDiretionRight": @(MoveDiretionRight),
   @"MoveDiretionBottom": @(MoveDiretionBottom),
   @"MoveDiretionTop": @(MoveDiretionTop),
}), MoveDiretionNone, integerValue)

@end
View Code

 

二、步骤

1、使用xcode创建一个名为LoginManager的静态库。

2、打开静态库,将上面贴出来的已经实现好了的Native模块LoginManager API组件的类全部拷贝进去或进行替换。

3、选择Build Settings,配置Header Search Paths路径。

6、打开终端,初始化一个新的RN项目,随意设置一个名称为:LoginManagerTestProject。(本人安装的ReactNative版本较低)

//初始化
react-native init LoginManagerTestProject --version 0.44.3

7、进入目录node_modules。

//进入node_modules
cd LoginManagerTestProject/node_modules

8、创建要制作的第三库文件夹,指定名称为:react-native-login-manager。

//创建第三方名称
mkdir react-native-login-manager

9、进入这个第三方库文件夹。

//进入库文件
cd react-native-login-manager

10、创建ios文件夹。

//创建ios文件
mkdir ios

11、将之前创建的静态库中的根目录下的文件全部copy到这个RN工程LoginManagerTestProject/node_modules/react-native-login-manager/ios目录下。目录结构如下:

12、使用xcode打开这个RN工程LoginManagerTestProject,将静态库LoginManager的.xcodeproj文件 拖到 RN工程LoginManagerTestProject的Libraries文件下。

13、手动添加libLoginManager.a静态包,然后编译,如果编译不出错,则success。

14、使用终端或者webStorm等编程工具进入到RN工程LoginManagerTestProject/node_modules/react-native-login-manager目录下,创建index.js文件,它是整个原生模块的入口,我们这里只是将原生LoginManager模块类进行导出。此时也就完成了第三方库制作的第一步了,仅仅可以自己使用。 (还需要发布到npm上,分享给大家安装使用)

 

三、测试 

好了,咱先自己测试一下,看看行不行。结果是行的,

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们