RN-Android端集成阿里云图形验证代码分析
RN-Android端集成阿里云图形验证代码分析
RN-Android端集成阿里云图形验证代码分析
RN-Android端集成阿里云图形验证代码分析
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
package com.xiaota.xtbp;
import android.app.Activity;
import android.util.Log;
import com.alicom.gtcaptcha4.AlicomCaptcha4Client;
import com.alicom.gtcaptcha4.AlicomCaptcha4Config;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Iterator;
public class AlicomCaptchaModule extends ReactContextBaseJavaModule {
private final ReactApplicationContext reactContext;
private AlicomCaptcha4Client captchaClient;
private String verifyAPI;
private boolean isInitialized = false;
private static final String MODULE_NAME = "AlicomCaptchaModule";
private static final String EVENT_VERIFY_RESULT = "onVerifyResult";
private static final String TAG = "AlicomCaptcha";
public AlicomCaptchaModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Override
public String getName() {
return MODULE_NAME;
}
@ReactMethod
public void init(ReadableMap config, Promise promise) {
try {
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
promise.reject("NO_ACTIVITY", "无法获取当前Activity");
return;
}
// 获取配置参数
String captchaId = config.hasKey("captchaId") ?
config.getString("captchaId") : "a5dcff3aea5e15493c72cef0c3ee6d37";
if (config.hasKey("verifyAPI")) {
verifyAPI = config.getString("verifyAPI");
}
currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
// 创建配置参数
HashMap<String, Object> params = new HashMap<>();
params.put("loading", "");
params.put("displayMode", -1);
params.put("bgColor", "#FFFFFFFF");
params.put("protocol", "https://");
params.put("useLocalOffline", false);
// 构建配置
AlicomCaptcha4Config.Builder builder = new AlicomCaptcha4Config.Builder();
// .setDebug(false)
// .setResourcePath("https://static.geetest.com/v4/gt4-index.html")
// .setLanguage("zh")
// .setTimeOut(10000)
// .setCanceledOnTouchOutside(true)
// .setParams(params);
// 初始化客户端
captchaClient = AlicomCaptcha4Client.getClient(currentActivity);
captchaClient.setLogEnable(false);
captchaClient.init(captchaId, builder.build());
isInitialized = true;
Log.d(TAG, "阿里云验证SDK初始化成功");
promise.resolve(true);
} catch (Exception e) {
Log.e(TAG, "初始化失败", e);
promise.reject("INIT_ERROR", "初始化失败: " + e.getMessage());
}
}
});
} catch (Exception e) {
Log.e(TAG, "初始化异常", e);
promise.reject("INIT_ERROR", "初始化异常: " + e.getMessage());
}
}
@ReactMethod
public void startVerify() {
if (!isInitialized) {
sendErrorResult("NOT_INITIALIZED", "请先调用init方法初始化SDK");
return;
}
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
sendErrorResult("NO_ACTIVITY", "无法获取当前Activity");
return;
}
currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
// 清除之前的监听器,避免重复添加
captchaClient.destroy();
// 重新初始化客户端(简单处理,避免监听器冲突)
AlicomCaptcha4Config.Builder builder = new AlicomCaptcha4Config.Builder();
// .setDebug(false)
// .setResourcePath("https://static.geetest.com/v4/gt4-index.html")
// .setLanguage("zh")
// .setTimeOut(10000)
// .setCanceledOnTouchOutside(true);
captchaClient.init("a5dcff3aea5e15493c72cef0c3ee6d37", builder.build());
// 设置新的监听器
captchaClient.addOnSuccessListener(new AlicomCaptcha4Client.OnSuccessListener() {
@Override
public void onSuccess(boolean status, String response) {
handleSuccessResponse(status, response);
}
});
captchaClient.addOnFailureListener(new AlicomCaptcha4Client.OnFailureListener() {
@Override
public void onFailure(String error) {
handleFailureResponse(error);
}
});
// 开始验证
captchaClient.verifyWithCaptcha();
Log.d(TAG, "开始阿里云图形验证");
} catch (Exception e) {
Log.e(TAG, "启动验证失败", e);
sendErrorResult("VERIFY_ERROR", "启动验证失败: " + e.getMessage());
}
}
});
}
private void handleSuccessResponse(boolean status, String response) {
try {
WritableMap resultParams = Arguments.createMap();
resultParams.putBoolean("success", status);
resultParams.putString("code", status ? "1" : "0");
// resultParams.putString("result", response);
// 创建result对象,包含所有响应数据
WritableMap resultData = Arguments.createMap();
if (status && response != null && !response.isEmpty()) {
try {
JSONObject responseJson = new JSONObject(response);
// 将response中的所有字段放入result对象
Iterator<String> keys = responseJson.keys();
while (keys.hasNext()) {
String key = keys.next();
Object value = responseJson.get(key);
if (value instanceof String) {
resultData.putString(key, (String) value);
} else if (value instanceof Boolean) {
resultData.putBoolean(key, (Boolean) value);
} else if (value instanceof Integer) {
resultData.putInt(key, (Integer) value);
} else if (value instanceof Double) {
resultData.putDouble(key, (Double) value);
} else if (value instanceof Long) {
resultData.putDouble(key, ((Long) value).doubleValue());
} else if (value instanceof Float) {
resultData.putDouble(key, ((Float) value).doubleValue());
} else {
resultData.putString(key, value.toString());
}
}
} catch (Exception e) {
Log.e(TAG, "解析JSON响应失败", e);
// 如果解析失败,将原始响应放入result
resultData.putString("rawResponse", response);
}
}
// 将result对象放入外层
resultParams.putMap("result", resultData);
if (status) {
JSONObject responseJson = new JSONObject(response);
if (responseJson.has("token")) {
resultParams.putString("verifyToken", responseJson.getString("token"));
}
resultParams.putString("message", "验证成功");
} else {
resultParams.putString("message", "验证失败");
}
sendEvent(EVENT_VERIFY_RESULT, resultParams);
} catch (Exception e) {
sendErrorResult("PARSE_ERROR", "解析验证结果失败");
}
}
private void handleFailureResponse(String error) {
WritableMap errorParams = Arguments.createMap();
errorParams.putBoolean("success", false);
errorParams.putString("code", "VERIFY_ERROR");
errorParams.putString("message", error);
sendEvent(EVENT_VERIFY_RESULT, errorParams);
}
@ReactMethod
public void destroy() {
if (captchaClient != null) {
captchaClient.destroy();
captchaClient = null;
}
isInitialized = false;
Log.d(TAG, "销毁阿里云验证SDK资源");
}
private void sendErrorResult(String code, String message) {
WritableMap errorParams = Arguments.createMap();
errorParams.putBoolean("success", false);
errorParams.putString("code", code);
errorParams.putString("message", message);
sendEvent(EVENT_VERIFY_RESULT, errorParams);
}
private void sendEvent(String eventName, WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
}
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
package com.xiaota.xtbp;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AlicomCaptchaPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AlicomCaptchaModule(reactContext));
return modules;
}
}
一、基础语法与结构
1. 包声明(Package Declaration)
java
package com.xiaota.xtbp;
- 定义类所在的包路径,必须是文件的第一行有效代码
2. 导入语句(Import Statements)
import android.app.Activity;
import android.util.Log;
import com.facebook.react.bridge.*;
- 用于引入其他包中的类
- Android 系统包:
**android.*** - React Native 包:
**com.facebook.react.bridge.*** - 第三方SDK包:
**com.alicom.gtcaptcha4.***
3. 类定义(Class Definition)
java
public class AlicomCaptchaModule extends ReactContextBaseJavaModule
**public**:访问修饰符,表示该类是公开的**extends**:继承,表示该类继承自**ReactContextBaseJavaModule**
4. 常量定义
private static final String MODULE_NAME = "AlicomCaptchaModule";
private static final String EVENT_VERIFY_RESULT = "onVerifyResult";
**static final**:定义常量,值不可修改- 命名规范:全大写,下划线分隔
5. 成员变量(Instance Variables)
private final ReactApplicationContext reactContext;
private AlicomCaptcha4Client captchaClient;
private String verifyAPI;
private boolean isInitialized = false;
- 类的属性,用于存储对象状态
- 常用修饰符:
**private**,**protected**,**public**
二、React Native 交互相关
1. 模块命名
@Override
public String getName() {
return MODULE_NAME;
}
- 必须重写的方法,返回模块名(JS端调用的名称)
2. 导出方法给 JS 调用
@ReactMethod
public void init(ReadableMap config, Promise promise) {
// 方法实现
}
**@ReactMethod**:注解,表示该方法可被 JS 端调用**ReadableMap**:从 JS 传递过来的对象(类似字典)**Promise**:用于异步回调(resolve/reject)
3. 向 JS 端发送事件
private void sendEvent(String eventName, WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
- 使用
**RCTDeviceEventEmitter**发送事件到 JS **WritableMap**:可写入的Map,用于构造要传递的数据
4. 数据类型转换
// JS对象 → Java
ReadableMap config;
String captchaId = config.getString("captchaId");
// Java → JS对象
WritableMap resultParams = Arguments.createMap();
resultParams.putBoolean("success", true);
resultParams.putString("message", "成功");
**Arguments.createMap()**:创建空的WritableMap- 各种put方法:
**putString**,**putBoolean**,**putInt**,**putDouble**,**putMap**
三、Android 特有知识点
1. Activity 相关
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
// 处理无Activity情况
return;
}
**getCurrentActivity()**:获取当前React Native所在的Activity- 所有UI操作必须在有Activity的情况下进行
2. 主线程UI操作
currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
// 在这里执行UI操作
captchaClient.verifyWithCaptcha();
}
});
- Android要求UI操作必须在主线程执行
**runOnUiThread()**:将代码抛到主线程执行
3. 日志打印
Log.d(TAG, "调试信息"); // Debug
Log.i(TAG, "普通信息"); // Info
Log.e(TAG, "错误信息"); // Error
- 用于调试和记录运行状态
- 不同级别:VERBOSE, DEBUG, INFO, WARN, ERROR
4. 异常处理
try {
// 可能出错的代码
} catch (Exception e) {
Log.e(TAG, "错误信息", e);
promise.reject("ERROR_CODE", "错误描述");
}
**try-catch**:捕获和处理异常- 良好的异常处理是Android开发的必备技能
四、React Package 注册
1. 实现 ReactPackage 接口
java
public class AlicomCaptchaPackage implements ReactPackage
- 必须实现
**ReactPackage**接口
2. 注册Native模块
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AlicomCaptchaModule(reactContext));
return modules;
}
- 在此处添加自定义的Native模块
- React Native启动时会自动扫描并注册这些模块
3. 空视图管理器
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
- 如果模块不包含自定义UI组件,返回空列表
五、常用工具类
1. JSON 处理
import org.json.JSONObject;
// 解析JSON字符串
JSONObject responseJson = new JSONObject(response);
String token = responseJson.getString("token");
2. 集合类
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// 创建列表
List<NativeModule> modules = new ArrayList<>();
六、代码结构总结
一个典型的React Native Android Native模块包含:
- 模块类:继承
**ReactContextBaseJavaModule****getName()**- 返回模块名**@ReactMethod**- 导出给JS调用的方法- 事件发送机制
- Package类:实现
**ReactPackage**- 注册模块到React Native
- Android特性:
- Activity生命周期感知
- 主线程UI操作
- 异常处理
- 日志记录
本文由作者按照 CC BY 4.0 进行授权