RN-iOS端集成阿里云图形验证代码分析
RN-iOS端集成阿里云图形验证代码分析
RN-iOS端集成阿里云图形验证代码分析
RN-iOS端集成阿里云图形验证代码分析
1
2
3
4
5
6
7
8
9
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#import <AlicomCaptcha4/AlicomCaptcha4.h>
@interface RCTAlicomCaptchaModule : RCTEventEmitter <RCTBridgeModule, AlicomCaptcha4SessionTaskDelegate>
@property (nonatomic, strong) AlicomCaptcha4Session *captchaSession;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//
// RCTAlicomCaptchaModule.m
// XTBP
//
// Created by 胡涛 on 2025/8/26.
//
#import "RCTAlicomCaptchaModule.h"
// 您自己或公司申请的验证 ID
#define CaptchaID @"a5dcff3aea5e15493c72cef0c3ee6d37"
@interface RCTAlicomCaptchaModule()
@property (nonatomic, copy) RCTPromiseResolveBlock initResolve;
@property (nonatomic, copy) RCTPromiseRejectBlock initReject;
@property (nonatomic, strong) NSString *verifyAPI;
@end
@implementation RCTAlicomCaptchaModule
RCT_EXPORT_MODULE(AlicomCaptchaModule);
- (NSArray<NSString *> *)supportedEvents {
return @[@"onVerifyResult", @"onCaptchaError", @"onCaptchaEvent"];
}
- (AlicomCaptcha4Session *)captchaSession {
if (!_captchaSession) {
AlicomCaptcha4SessionConfiguration *config = [AlicomCaptcha4SessionConfiguration defaultConfiguration];
// 可选配置(根据官方Demo)
// config.resourcePath = @"https://static.geetest.com/v4/gt4-index.html";
// config.apiServer = @"192.168.1.147";
// config.protocol = @"http";
// config.backgroundColor = [UIColor blackColor];
_captchaSession = [AlicomCaptcha4Session sessionWithCaptchaID:CaptchaID configuration:config];
_captchaSession.delegate = self;
NSLog(@"AlicomCaptcha4Session init time: %.0f", [[NSDate date] timeIntervalSince1970] * 1000);
}
return _captchaSession;
}
RCT_EXPORT_METHOD(init:(NSDictionary *)config resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
self.initResolve = resolve;
self.initReject = reject;
// 存储校验接口地址(如果有)
if (config[@"verifyAPI"]) {
self.verifyAPI = config[@"verifyAPI"];
}
// 初始化session(懒加载)
AlicomCaptcha4Session *session = [self captchaSession];
if (session) {
resolve(@(YES));
} else {
reject(@"INIT_ERROR", @"初始化AlicomCaptcha4Session失败", nil);
}
}
RCT_EXPORT_METHOD(startVerify) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"AlicomCaptcha4Session verify start");
[self.captchaSession verify];
});
}
RCT_EXPORT_METHOD(configure:(NSDictionary *)config) {
// 可以添加配置项,如修改resourcePath、apiServer等
if (config[@"resourcePath"]) {
self.captchaSession.configuration.resourcePath = config[@"resourcePath"];
}
if (config[@"apiServer"]) {
self.captchaSession.configuration.apiServers = config[@"apiServer"];
}
if (config[@"protocol"]) {
self.captchaSession.configuration.protocol = config[@"protocol"];
}
}
#pragma mark - AlicomCaptcha4SessionTaskDelegate
- (void)alicomCaptchaSession:(AlicomCaptcha4Session *)captchaSession didReceive:(NSString *)code result:(NSDictionary *)result {
NSLog(@"AlicomCaptcha4Session result: %@, code: %@", result, code);
NSMutableDictionary *resultDict = [NSMutableDictionary dictionary];
if ([@"1" isEqualToString:code]) {
// 验证成功
resultDict[@"success"] = @(YES);
resultDict[@"code"] = code;
resultDict[@"result"] = result;
if (result && result.count > 0) {
// 将结果中的所有字段都传递给JS
[result enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([key isKindOfClass:[NSString class]]) {
if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
resultDict[key] = obj;
}
}
}];
// 如果有校验接口,进行二次校验
if (self.verifyAPI && [self.verifyAPI length] > 0) {
[self performSecondaryVerification:result];
}
}
} else {
// 验证失败或取消
resultDict[@"success"] = @(NO);
resultDict[@"code"] = code;
resultDict[@"message"] = @"请正确完成验证码";
}
// 发送事件到React Native
[self sendEventWithName:@"onVerifyResult" body:resultDict];
}
- (void)alicomCaptchaSession:(AlicomCaptcha4Session *)captchaSession didReceiveError:(AlicomC4Error *)error {
NSLog(@"AlicomCaptcha4Session error: %@", error.description);
NSDictionary *errorDict = @{
@"success": @(NO),
@"code": error.code ?: @"UNKNOWN_ERROR",
@"message": error.description ?: @"验证过程中发生错误"
};
[self sendEventWithName:@"onCaptchaError" body:errorDict];
}
#pragma mark - Secondary Verification
- (void)performSecondaryVerification:(NSDictionary *)result {
if (!self.verifyAPI) return;
__block NSMutableArray<NSString *> *kvPairs = [NSMutableArray array];
[result enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([key isKindOfClass:[NSString class]] &&
[obj isKindOfClass:[NSString class]]) {
NSString *kvPair = [NSString stringWithFormat:@"%@=%@", key, obj];
[kvPairs addObject:kvPair];
}
}];
NSString *formStr = [kvPairs componentsJoinedByString:@"&"];
NSData *data = [formStr dataUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:self.verifyAPI];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
request.HTTPBody = data;
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error && data) {
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Secondary verification result: %@", msg);
// 发送二次校验结果到JS
NSDictionary *verifyResult = @{
@"type": @"secondary_verify",
@"result": msg ?: @""
};
[self sendEventWithName:@"onCaptchaEvent" body:verifyResult];
} else {
NSLog(@"Secondary verification error: %@", error);
}
}] resume];
}
@end
一、头文件(.h)中的知识点
1. **#import**
- 用于引入其他头文件(系统或自定义)。
例如:
#import <React/RCTBridgeModule.h>
#import <AlicomCaptcha4/AlicomCaptcha4.h>
2. **@interface**
- 用于声明一个类。
语法:
@interface ClassName : SuperClass <Protocol1, Protocol2>
@end
示例:
@interface RCTAlicomCaptchaModule : RCTEventEmitter <RCTBridgeModule, AlicomCaptcha4SessionTaskDelegate>
@end
3. **@property**
- 用于声明类的属性(成员变量),自动生成 getter 和 setter。
语法:
- objc@property (nonatomic, strong) Type *propertyName;
- 常用修饰符:
**strong**:强引用(默认)**weak**:弱引用**copy**:拷贝一份(常用于 NSString)**nonatomic**:非原子性(提高性能,多线程需自行处理同步)
二、实现文件(.m)中的知识点
1. **#define**
- 定义宏常量,常用于配置或全局字符串。
示例:#define CaptchaID @”a5dcff3aea5e15493c72cef0c3ee6d37”
2. **@implementation**
- 实现类中声明的方法。
语法:
@implementation ClassName
// 方法实现
@end
3. **RCT_EXPORT_MODULE**
- React Native 宏,用于导出模块,使 JS 端可调用。
- 可选参数为模块名,若不传则默认为类名。
示例:
RCT_EXPORT_MODULE(AlicomCaptchaModule);
4. **RCT_EXPORT_METHOD**
- 导出方法给 JS 端调用。
- 方法必须是 void 返回值。
示例:
RCT_EXPORT_METHOD(startVerify) {
// 实现
}
5. **RCTPromiseResolveBlock** 和 **RCTPromiseRejectBlock**
- 用于 Promise 风格的异步方法回调。
示例:
RCT_EXPORT_METHOD(init:(NSDictionary *)config resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
// 成功:resolve(@(YES));
// 失败:reject(@"ERROR_CODE", @"错误信息", nil);
}
6. **dispatch_async(dispatch_get_main_queue(), ^{ ... })**
- 将代码块抛到主线程执行(UI 操作必须在主线程)。
示例:
dispatch_async(dispatch_get_main_queue(), ^{
[self.captchaSession verify];
});
7. **NSLog**
- 打印日志,调试用。
示例:
NSLog(@”AlicomCaptcha4Session init time: %.0f”, [[NSDate date] timeIntervalSince1970] * 1000);
8. **NSDictionary** / **NSMutableDictionary**
- 字典类型,用于键值对存储。
示例:
NSDictionary *dict = @{@"key": @"value"};
NSMutableDictionary *mutableDict = [NSMutableDictionary dictionary];
9. **NSString**
- 字符串类型,常用
**@""**语法创建。
示例:
NSString *str = @”Hello”;
10. **NSURLSession**
- 用于发起网络请求。
示例:
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// 回调处理
}];
[task resume];
三、React Native 交互相关
1. 继承 **RCTEventEmitter**
- 用于向 JS 端发送事件。
- 必须实现
**supportedEvents**方法。
示例:
- (NSArray<NSString *> *)supportedEvents {
return @[@"onVerifyResult", @"onCaptchaError"];
}
2. 发送事件到 JS
- 使用
**sendEventWithName:body:**方法。
示例:
[self sendEventWithName:@”onVerifyResult” body:resultDict];
四、协议(Protocol / Delegate)
1. 遵守协议
- 在
**@interface**中声明遵守的协议。
示例:
<RCTBridgeModule, AlicomCaptcha4SessionTaskDelegate>
2. 实现协议方法
- 在
**@implementation**中实现协议中定义的方法。
示例:
- (void)alicomCaptchaSession:(AlicomCaptcha4Session *)captchaSession didReceive:(NSString *)code result:(NSDictionary *)result {
// 实现
}
五、其他常用语法
1. 懒加载(Lazy Loading)
- 使用 getter 方法延迟初始化属性。
示例:
- (AlicomCaptcha4Session *)captchaSession {
if (!_captchaSession) {
_captchaSession = [AlicomCaptcha4Session sessionWithCaptchaID:CaptchaID configuration:config];
}
return _captchaSession;
}
2. 条件判断与类型检查
- 常用
**isKindOfClass:**判断类型。
示例:
if ([key isKindOfClass:[NSString class]]) {
// 处理字符串
}
当然。在 iOS/macOS 开发中,文件后缀 **.h** 和 **.m** 的全称和含义如下:
1.
**.h**文件
本文由作者按照 CC BY 4.0 进行授权