React Native 原生密碼鍵盤插件

一:介紹

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//無標題

帶有文本框的鍵盤:


有支付密碼格的鍵盤:


打開默認瀏覽器和打開自定義瀏覽器,具體的實現思路如下:

  1. 新建CustomKeyboard類,實現RCTBridgeModule協議

  2. 添加RCT_EXPORT_MODULE()宏

  3. 添加React Native跟控制器

  4. 聲明被JavaScript 調用的方法

  5. 新建數字鍵盤FBYNumKeyBord類,實現相應視圖及功能

  6. 新建字母鍵盤FBYWordKeyBord類,實現相應視圖及功能

  7. 新建純數字鍵盤FBYNumOnlyKeyBord類,實現相應視圖及功能

  8. 新建符號鍵盤FBYSymbolKeyBord類,實現相應視圖及功能

  9. 新建符號鍵盤FBYCustomKeyBord類,實現鍵盤類型切換功能

  10. 實現根據密碼判斷密碼強度和長度功能

  11. 實現輸出密碼SM3加密功能

  12. 根據傳參分析調用自定義鍵盤

  13. 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

如果哪裏有什麼不對或者不足的地方,還望讀者多多提意見或建議

如需轉載請聯繫我,經過授權方可轉載,謝謝

本篇已同步到個人博客:FBY展菲

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章