一: 介绍
React Native (简称 RN) 是 Facebook 于 2015 年 4 月开源的跨平台移动应用开发框架, 是 Facebook 早先开源的 JS 框架 React 在原生移动应用平台的衍生产物, 目前支持 iOS 和安卓两大平台. RN 使用 JavaScript 语言, 类似于 HTML 的 JSX, 以及 CSS 来开发移动应用, 因此熟悉 Web 前端开发的技术人员只需很少的学习就可以进入移动应用开发领域.
在 React Native 移动平台项目开发中, 除了 React Native 提供的封装好的部分插件和原声组建外, 在实际的项目中还需要使用到很多其他的插件, 比如网络请求, 数据库, 相机, 相册, 通讯录, 视频播放器, 浏览器, 蓝牙连接, 图片处理, 消息推送, 地图, 统计, 埋点等等 App 开发中需要用到的功能, 都为 IDE 开发平台提供封装好的插件, 以便项目开发使用.
另外, 这些博文都是来源于我日常开发中的技术总结, 在时间允许的情况下, 我会针对技术点分别分享 iOS,Android 两个版本, 如果有其他技术点需要, 可在文章后留言, 我会尽全力帮助大家. 这篇文章重点介绍原生密码键盘插件的开发与使用
二: 实现思路分析
原生密码键盘插件是需要实现自定以键盘包含数字, 大写字母, 小写字母, 特殊字符四种切换方式, 并且需要实现随机键盘和非随机键盘模式. 实现根据密码包含数字, 大写字母, 小写字母, 特殊字符种类判断密码强度和长度. 为了密码的安全考虑, 实现对输出密码进行 SM3 加密. 实现键盘类型, 其中包括以下 6 种类型:
FBYCustomKeyBordType_NumWord,// 数字及字母键盘 FBYCustomKeyBordType_WordNum,// 字母及数字键盘 FBYCustomKeyBordType_NumWordSymbol,// 数字及字母, 标点键盘 FBYCustomKeyBordType_WordNumSymbol,// 字母及数字, 标点键盘 FBYCustomKeyBordType_Num,// 仅数字键盘 FBYCustomKeyBordType_Word// 仅字母键盘
基本键盘截图如下:
实现键盘视图显示类型, 其中包括以下 5 种类型:
FBYCustomKeyBordShowType_Common,// 普通 FBYCustomKeyBordShowType_Text,// 文本框 FBYCustomKeyBordShowType_Pass,// 密码 FBYCustomKeyBordShowType_PayPass,// 支付密码格 FBYCustomKeyBordShowType_NoTitle// 无标题
带有文本框的键盘:
有支付密码格的键盘:
打开默认浏览器和打开自定义浏览器, 具体的实现思路如下:
新建 CustomKeyboard 类, 实现 RCTBridgeModule 协议
添加 RCT_EXPORT_MODULE() 宏
添加 React Native 跟控制器
声明被 JavaScript 调用的方法
新建数字键盘 FBYNumKeyBord 类, 实现相应视图及功能
新建字母键盘 FBYWordKeyBord 类, 实现相应视图及功能
新建纯数字键盘 FBYNumOnlyKeyBord 类, 实现相应视图及功能
新建符号键盘 FBYSymbolKeyBord 类, 实现相应视图及功能
新建符号键盘 FBYCustomKeyBord 类, 实现键盘类型切换功能
实现根据密码判断密码强度和长度功能
实现输出密码 SM3 加密功能
根据传参分析调用自定义键盘
JavaScript 调用浏览器方法
三: 实现源码分析
1. 新建 CustomKeyboard 类, 实现 RCTBridgeModule 协议
新建继承 NSObject 的 CustomKeyboard 类, 并实现 RCTBridgeModule 协议
- // CustomKeyboard.h
- #import <Foundation/Foundation.h>
- #import <React/RCTBridgeModule.h>
- #import <UIKit/UIKit.h>
- @interface CustomKeyboard : NSObject<RCTBridgeModule>
- @end
2. 添加 RCT_EXPORT_MODULE() 宏
为了实现 RCTBridgeModule 协议, CustomKeyboard 的类需要包含 RCT_EXPORT_MODULE() 宏. 并在这个宏里面添加一个参数 "KeybordPlugin" 用来指定在 JavaScript 中访问这个模块的名字. 如果你不指定, 默认就会使用这个 Objective-C 类的名字. 如果类名以 RCT 开头, 则 JavaScript 端引入的模块名会自动移除这个前缀.
- // CustomKeyboard.m
- #import "CustomKeyboard.h"
- @implementation CustomKeyboard
- RCT_EXPORT_MODULE(KeybordPlugin);
- @end
3. 添加 React Native 跟控制器
如果不添加 React Native 跟控制器, view 将不能正常显示出来, 实现方法如下:
- // CustomKeyboard.m
- #import "CustomKeyboard.h"
- #import <React/RCTUtils.h>
- @implementation CustomKeyboard
- RCT_EXPORT_MODULE(KeybordPlugin);
- @end
引入 < React/RCTUtils.h > 之后, 在视图初始化或者显示的时候, 按照如下方法调用即可
UIViewController *vc = RCTPresentedViewController();
4. 声明被 JavaScript 调用的方法
React Native 需要明确的声明要给 JavaScript 导出的方法, 否则 React Native 不会导出任何方法. 声明通过 RCT_EXPORT_METHOD() 宏来实现:
- // CustomKeyboard.m
- #import "CustomKeyboard.h"
- #import <React/RCTUtils.h>
- @implementation CustomKeyboard
- RCT_EXPORT_MODULE(KeybordPlugin);
- RCT_EXPORT_METHOD(onKeyboard:(NSDictionary *)arguments
- :(RCTResponseSenderBlock)sucessCallback
- :(RCTResponseSenderBlock)failCallback)
- {
- NSLog(@"调起原生密码键盘方法");
- }
- @end
5. 新建数字键盘 FBYNumKeyBord 类, 实现相应视图及功能
在数字键盘 FBYNumKeyBord 类中, 视图包含 0-9 数字按钮, ABC 字母切换按钮,@%# 特殊字符切换按钮, 回删按钮, 完成按钮和取消按钮. 实现相应按钮的点击功能以及实现随机键盘和非随机键盘两种模式. 效果图:
核心代码如下:
- //FBYNumKeyBord.m
- - (void)setRandom:(BOOL)random{
- _random = random;
- if (random) {
- NSMutableArray *newArray = [NSMutableArray arrayWithArray:self.numArray];
- for(int i = 0; i<self.numArray.count; i++)
- {
- int m = (arc4random() % (self.numArray.count - i)) + i;
- [newArray exchangeObjectAtIndex:i withObjectAtIndex: m];
- }
- self.numArray = newArray;
- for (UIButton *btn in self.subviews) {
- [btn removeFromSuperview];
- }
- [self addControl];
- }
- }
6. 新建字母键盘 FBYWordKeyBord 类, 实现相应视图及功能
在数字键盘 FBYWordKeyBord 类中, 视图包含 26 个字母按钮, 大小写切换按钮, 123 数字键盘切换按钮,@%# 特殊字符切换按钮, 回删按钮, 完成按钮和取消按钮. 实现相应按钮的点击功能以及实现随机键盘和非随机键盘两种模式. 效果图:
核心代码如下:
- //FBYWordKeyBord.m
- for (int i = 0; i< 26; i++) {
- FBYCustomKeyBordButton *btn = [FBYCustomKeyBordButton buttonWithTitle:self.wordArray[i] tag:i delegate:self];
- [btn addTarget:self action:@selector(btnTouchDown:) forControlEvents:(UIControlEventTouchDown)];
- [btn addTarget:self action:@selector(btnTouchCancel:) forControlEvents:(UIControlEventTouchUpInside)];
- [btn addTarget:self action:@selector(btnTouchCancel:) forControlEvents:(UIControlEventTouchUpOutside)];
- [btn addTarget:self action:@selector(btnTouchCancel:) forControlEvents:(UIControlEventTouchCancel)];
- [btnArray addObject:btn];
- [self addSubview:btn];
- }
7. 新建纯数字键盘 FBYNumOnlyKeyBord 类, 实现相应视图及功能
在数字键盘 FBYNumOnlyKeyBord 类中, 视图包含 0-9 数字按钮, 回删按钮, 完成按钮和取消按钮. 实现相应按钮的点击功能以及实现随机键盘和非随机键盘两种模式. 效果图:
核心代码如下:
- //FBYNumOnlyKeyBord.m
- for (int i=0;i<self.btnArray.count;i++) {
- UIButton *btn =self.btnArray[i];
- if(i<9){
- btn.frame = CGRectMake(btn.tag % 3 * (btnW ), btn.tag / 3 * (btnH ), btnW, btnH);
- }else if (i==9){
- btn.frame = CGRectMake( 1 * (btnW ), 3* (btnH ), btnW, btnH);
- }else if (i==10){
- btn.frame = CGRectMake( 0* (btnW ), 3* (btnH ) , btnW, btnH);
- }else if (i==11){
- btn.frame = CGRectMake( 2* (btnW ), 3* (btnH ), btnW, btnH);
- }else if (i==12){
- btn.frame = CGRectMake( 0* (btnW ), 3* (btnH ), btnW, btnH);
- }
- }
8. 新建符号键盘 FBYSymbolKeyBord 类, 实现相应视图及功能
在数字键盘 FBYSymbolKeyBord 类中, 视图包含 30 种特殊字符按钮, 123 数字键盘切换按钮, ABC 字母切换按钮, 回删按钮, 完成按钮和取消按钮. 实现相应按钮的点击功能以及实现随机键盘和非随机键盘两种模式. 效果图:
核心代码如下:
- //FBYSymbolKeyBord.m
- - (NSArray *)symbolArray{
- if (!_symbolArray) {
_symbolArray = @[@"*",@"/",@":",@";",@"(",@")",@"[",@"]",@"$",@"=",@"!",@"^",@"&",@"%",@"+",@"-",@"¥",@"?",@"{",@"}",@"#",@"_",@"\\",@"|",@"~",@"`",@"∑",@"€",@"£",@"."];
- }
- return _symbolArray;
- }
- - (void)addControl{
- NSMutableArray *btnArray = [NSMutableArray array];
- for (int i = 0; i < 30; i++) {
- FBYCustomKeyBordButton *btn = [FBYCustomKeyBordButton buttonWithTitle:self.symbolArray[i] tag:i delegate:self];
- [btn addTarget:self action:@selector(btnTouchDown:) forControlEvents:(UIControlEventTouchDown)];
- [btn addTarget:self action:@selector(btnTouchCancel:) forControlEvents:(UIControlEventTouchUpInside)];
- [btn addTarget:self action:@selector(btnTouchCancel:) forControlEvents:(UIControlEventTouchUpOutside)];
- [btn addTarget:self action:@selector(btnTouchCancel:) forControlEvents:(UIControlEventTouchCancel)];
- [self addSubview:btn];
- [btnArray addObject:btn];
- }
- }
9. 新建 FBYCustomKeyBord 类, 实现键盘类型切换功能
FBYCustomKeyBord 类中根据 JS 调用键盘时传入的参数, 来实现何种键盘模式, 实现键盘类型, 共有 6 种类型: 数字及字母, 字母及数字, 数字及字母特殊字符, 字母及数字特殊字符, 仅数字, 仅字母. 键盘视图显示类型, 共包括 5 种类型: 普通, 文本框, 密码, 支付密码格, 无标题. 核心代码如下:
- -(void)setKeybordType:(FBYCustomKeyBordType)keybordType{
- _keybordType=keybordType;
- [self.numPad removeFromSuperview];
- if(_keybordType==FBYCustomKeyBordType_NumWord){
- self.numPad.random=self.random;
- self.numPad.delegate=self;
- [self addSubview:self.numPad];
- }else if(_keybordType==FBYCustomKeyBordType_WordNum){
- self.wordPad.random=self.random;
- self.wordPad.delegate=self;
- [self addSubview:self.wordPad];
- }else if(_keybordType==FBYCustomKeyBordType_Num){
- self.numOnlyPad.random=self.random;
- self.numOnlyPad.delegate=self;
- [self addSubview:self.numOnlyPad];
- }else if(_keybordType==FBYCustomKeyBordType_NumWordSymbol){
- self.numPad.random=self.random;
- self.numPad.delegate=self;
- [self addSubview:self.numPad];
- }else if(_keybordType==FBYCustomKeyBordType_Word){
- self.wordPad.random=self.random;
- self.wordPad.delegate=self;
- [self addSubview:self.wordPad];
- }else if (keybordType==FBYCustomKeyBordType_WordNumSymbol){
- self.wordPad.random=self.random;
- self.wordPad.delegate=self;
- [self addSubview:self.wordPad];
- }
- }
10. 实现根据密码判断密码强度和长度功能
根据密码字符串获取其长度, 代码如下:
- //FBYCustomKeyBord.m
- #pragma mark 长度计算
- -(NSUInteger)messageLength:(NSString *)message{
- NSString *msg=[message copy];
- NSUInteger length= msg.length;
- NSLog(@"%lu",(unsigned long)length);
- return length;
- }
根据密码字符串 message, 通过正则校验, 判断字符串中包含几种字符, 进而判断其密码强度. 总共是数字, 大写字母, 小写字母, 特殊字符四种状态, 包含两种强度为弱, 包含三种强度为中, 包含四种强度为强, 代码如下:
- //FBYCustomKeyBord.m
- #pragma mark 强度计算
- -(NSUInteger)messageStrength:(NSString *)message{
- NSString *msg=[message copy];
- NSUInteger length= msg.length;
- BOOL capitalBool = NO;
- BOOL lowercaseBool = NO;
- BOOL numberBool = NO;
- BOOL stringBool = NO;
- NSString* result1;
- NSString* result2;
- NSString* result3;
- NSString* result4;
- for (int i = 0; i < length; i++) {
- char commitChar = [msg characterAtIndex:i];
- if((commitChar>64)&&(commitChar<91)){
- NSLog(@"字符串中含有大写英文字母");
- capitalBool = YES;
- }else if((commitChar>96)&&(commitChar<123)){
- NSLog(@"字符串中含有小写英文字母");
- lowercaseBool = YES;
- }else if((commitChar>47)&&(commitChar<58)){
- NSLog(@"字符串中含有数字");
- numberBool = YES;
- }else{
- NSLog(@"字符串中含有空格");
- stringBool = YES;
- }
- }
- result1 = [NSString stringWithFormat:@"%d",capitalBool];
- result2 = [NSString stringWithFormat:@"%d",lowercaseBool];
- result3 = [NSString stringWithFormat:@"%d",numberBool];
- result4 = [NSString stringWithFormat:@"%d",stringBool];
- NSMutableArray* resultArray = [[NSMutableArray alloc] init];
- [resultArray addObject:[NSString stringWithFormat:@"%@",result1]];
- [resultArray addObject:[NSString stringWithFormat:@"%@",result2]];
- [resultArray addObject:[NSString stringWithFormat:@"%@",result3]];
- [resultArray addObject:[NSString stringWithFormat:@"%@",result4]];
- int intResult=0;
- for (int j=0; j<[resultArray count]; j++)
- {
- if ([[resultArray objectAtIndex:j] isEqualToString:@"1"])
- {
- intResult++;
- }
- }
- NSUInteger result;
- if (intResult == 4){
- result = 3;
- }else if (intResult == 3){
- result = 2;
- }else if (intResult == 2){
- result = 1;
- }else{
- result = 0;
- }
- return result;
- }
11. 实现输出密码 SM3 加密功能
这里的密码加密采用的是国密 SM3 加密方式, 代码如下:
- #pragma mark 加密设置
- -(NSString *)encryptMessage:(NSString *)message{
- NSString *msg=[message copy];
- return [self sm3:msg];
- }
- #pragma mark - 对字符串做 sm3 处理
- - (NSString *) sm3:(NSString *) input
- {
- NSData *inputData = [input dataUsingEncoding:NSUTF8StringEncoding];
- NSData *outputData = [CustomKBSM3Coded sm3_hashWithPainData:inputData];
- //NSString *outputString = [GTMBase64 stringByEncodingData:outputData];
- NSString *outputString = [self convertDataToHexStr:outputData];
- NSString *upper = [outputString uppercaseString];
- return upper;
- }
12. 根据传参打开浏览器
此浏览器插件支持打开自定义浏览器和打开默认浏览器, 具体使用哪种方法打开浏览器, 需要 JavaScript 通过 arguments 字典以字段的形式传过来, 这里就使用 openType 字段.
- // CustomKeyboard.m
- #import "CustomKeyboard.h"
- #import <React/RCTUtils.h>
- @interface CustomKeyboard ()<FBYCustomKeyBordDelegate>
- @property(strong,nonatomic)RCTResponseSenderBlock sucessCallback;
- @property(strong,nonatomic)RCTResponseSenderBlock failCallback;
- @property (nonatomic, strong) FBYCustomKeyBord *keyBoard;
- @property(assign,nonatomic)FBYCustomKeyBordType keybordType;
- @property(assign,nonatomic)FBYCustomKeyBordShowType keybordShowType;
- @property(strong,nonatomic)NSString *tag;
- @property(strong,nonatomic)NSString *isUp;
- @end
- @implementation CustomKeyboard
- RCT_EXPORT_MODULE(KeybordPlugin);
- RCT_EXPORT_METHOD(open:(NSDictionary *)arguments
- withCompletionHandler:(RCTResponseSenderBlock)completion
- failureHandler:(RCTResponseSenderBlock)failure)
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.keyBoard = [FBYCustomKeyBord instance];
- self.keyBoard.delegate = self;
- self.sucessCallback = sucessCallback;
- self.failCallback = failCallback;
- NSString *isUp=@"1";
- NSString *isRandom=@"0";
- NSString *type=@"4";
- NSString *showType=@"0";
- NSString *isEncrypt=@"0";
- // 是否是随机键盘
- self.keyBoard.random = YES;
- self.keybordType = FBYCustomKeyBordType_Num;
- self.keybordShowType = FBYCustomKeyBordShowType_Common;
- self.keyBoard.keybordType = self.keybordType;
- // 弹起键盘或收起键盘
- self.keyBoard.keybordShowType = self.keybordShowType;
- dispatch_async(dispatch_get_main_queue(), ^{
- if ((isUp==nil) || isUp.intValue == 1) {
- [self.keyBoard popKeyBordInParent:RCTPresentedViewController()];
- } else {
- [self.keyBoard disappearSwitchBtnClickWithBlock:^{
- self.sucessCallback(@[@{SucessReslutCode:@"1",SucessData:@"ok"}]);
- CIBNSLog(@"成功调起密码键盘方法");
- }];
- }
- });
- });
- }
- // 键盘数据回调
- -(void)customKeybord:(FBYCustomKeyBord *)keybord didReturnMessage:(NSString *)message withLength:(NSUInteger)length withStrength:(NSUInteger)strength{
- if(self.tag == nil){
- self.tag = [CustomKeyboard getSecondTimeStringSince1970];
- }
- if (![self.isUp isEqualToString:@"0"]) {
- self.sucessCallback(@[@{SucessReslutCode:@"1",SucessData:@{@"pwdLength":[NSString stringWithFormat:@"%lu",(unsigned long)length],@"pwdStrong":[NSString stringWithFormat:@"%lu",strength],@"pwdValue":message}}]);
- NSLog(@"成功调起密码键盘方法");
- }
- }
13. JavaScript 调用浏览器方法
现在从 JavaScript 里可以这样调用这个方法:
- import { NativeModules } from "react-native";
- const CustomkeyBoardPlugin = NativeModules.KeybordPlugin;
- CustomkeyBoardPlugin.onKeyboard({isRandom:"1",isUp:"1",type:"4",showType:"3"},(msg) => {
- Alert.alert(JSON.stringify(msg));
- },(err) => {
- Alert.alert(JSON.stringify(err));
- });
希望可以帮助大家, 如有问题可加 QQ 技术交流群: 668562416
如果哪里有什么不对或者不足的地方, 还望读者多多提意见或建议
来源: https://juejin.im/post/5c0bc0a151882517165dd82c