App侧发送验证请求实践教程
本教程将介绍如何从App侧发起验证请求,将验证结果返回给H5侧,并提供Demo工程文件。
此方式接入推荐直接使用滑块或者拼图等验证形态,不建议使用无痕验证。无痕验证需要采集页面上的用户行为信息,并且需要一个动作去触发验证,而这种情况下开发者通常会使用JavaScript自动触发验证,这可能导致无痕验证不通过,同时也计算了一次验证费用。
使用WKWebView在iOS App中接入验证码2.0(Swift)
iOS应用中,可以通过WKWebView的window.webkit.messageHandlers
接口与H5页面进行JavaScript
交互,可以通过这个接口向原生代码发送消息,并且获取到原生代码处理的结果。通常,这种交互是异步的,因为它依赖于原生代码的处理和回调。然而,window.webkit.messageHandlers
本身并不直接支持Promise
或者async/await
机制。消息的发送通常是单向的,从JavaScript
发送到原生代码,而原生代码的回复则需要通过其他机制来实现。要让这种交互能够使用await
,需要构建一个Promise
并在原生代码处理完毕后通过某种方式(通常是一个回调函数)来解决这个Promise
。以下是一个简单的示例来说明如何实现这一点。
将captchaVerifyCallback
做如下修改:
// 在H5页面中定义一个函数,用于发送消息给原生代码,并返回一个Promise
async function sendMessageToNative(action, data) {
return new Promise((resolve, reject) => {
// 创建一个唯一的回调函数名称
const callbackName = `cb_${Math.random().toString(36).substring(2)}`;
// 将回调函数挂载到window对象上,以便原生代码可以调用
window[callbackName] = (response) => {
// 处理或显示iOS端返回的处理结果
console.log('iOS返回的验证结果', response);
resolve(JSON.parse(response)); // 注意格式转换
// 移除挂载的回调函数,避免内存泄露
delete window[callbackName];
};
console.log(action, data, window.webkit);
// 调用Java定义的JavaScript接口,发送消息给原生代码
window.webkit && window.webkit.messageHandlers[action].postMessage(JSON.stringify({
data,
callback: callbackName,
}));
});
}
// 使用async函数来调用sendMessageToNative,并等待原生代码的回复
// 业务请求(带验证码校验)回调函数
async function captchaVerifyCallback(captchaVerifyParam) {
// 1.调用sendMessageToNative方法获取验证结果
let result = {};
try {
console.log(captchaVerifyParam);
result = await sendMessageToNative('getVerifyResult', captchaVerifyParam);
console.log('iOS返回的验证结果:', result);
} catch (error) {
console.error('发生错误:', error);
// 错误处理/兼容逻辑
result = {
captchaResult: false,
bizResult: false,
};
}
// 如果是在App侧执行验证码是否通过/业务验证是否通过逻辑,则不需要下面的返回值,直接关闭H5即可
return {
captchaResult: result.captchaResult, // 验证码验证是否通过,boolean类型,必选
bizResult: result.bizReuslt, // 业务验证是否通过,boolean类型,可选;若为无业务验证结果的场景,bizResult可以为空
};
}
同时,参考如下示例修改Swift代码,将验证结果返回给H5页面,并根据业务需求决定在App侧或H5侧执行业务自定义提示逻辑:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "getVerifyResult", let messageBody = message.body as? String {
if let data = messageBody.data(using: .utf8) {
do {
if let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
// 解析JSON
let captchaVerifyParam = jsonObject["data"]as! String;
let callbackName = jsonObject["callback"] as! String;
// 用captchaVerifyParam请求后端接口拿到请求结果
let response: [String: Any] = [
"captchaResult": true,
"bizResult": true
]; // result可以转换为一个JSON字符串,注意传给H5之后的数据格式转换
do {
let jsonData = try JSONSerialization.data(withJSONObject: response, options: []);
// 将JSON数据转换为字符串
if let verifyResult = String(data: jsonData, encoding: .utf8) {
// 执行回调,传递结果回H5页面
sendJSONToWebView(jsonString: verifyResult, callbackName: callbackName);
// 根据result在App侧来执行业务自定义提示逻辑,H5中的onBizResultCallback可以置为空函数
}
} catch {
print("Error serializing JSON: \(error)")
}
}
} catch {
print("Failed to parse JSON: \(error)")
}
}
}
// 关闭webview
if message.name == "closeWebView" {
webView.removeFromSuperview();
}
}
// JavaScript 函数的调用
func sendJSONToWebView(jsonString: String, callbackName: String) {
let javascriptFunction = "\(callbackName)('\(jsonString)');"
webView.evaluateJavaScript(javascriptFunction) { (result, error) in
if let error = error {
print("Error calling JavaScript function: \(error)")
} else {
print("Sent JSON to WebView")
}
}
}
使用WebView在Android App中接入验证码2.0
在Android应用中,可以通过自定义Java的testJsInterface
接口与H5页面进行JavaScript
交互。可以通过这个接口向原生代码发送消息,并且获取到原生代码处理的结果。通常,这种交互是异步的,因为它依赖于原生代码的处理和回调。然而,window.testInterface
本身并不直接支持Promise
或者async/await
机制。消息的发送通常是单向的,从JavaScript
发送到原生代码,而原生代码的回复则需要通过其他机制来实现。要让这种交互能够使用await
,需要构建一个Promise
并在原生代码处理完毕后通过某种方式(通常是一个回调函数)来解决这个Promise
。以下是一个简单的示例来说明如何实现这一点。
将captchaVerifyCallback
做如下修改:
// 在H5页面中定义一个函数,用于发送消息给原生代码,并返回一个Promise
async function sendMessageToNative(action, data) {
return new Promise((resolve, reject) => {
// 创建一个唯一的回调函数名称
const callbackName = 'cb_' + Math.random().toString(36).substring(2);
// 将回调函数挂载到window对象上,以便原生代码可以调用
window[callbackName] = (response) => {
// 处理或显示Android端返回的处理结果
console.log('安卓返回的验证结果', response);
resolve(JSON.parse(response)); // 注意格式转换
// 移除挂载的回调函数,避免内存泄露
delete window[callbackName];
};
// 调用Java定义的JavaScript接口,发送消息给原生代码
window.testInterface && window.testInterface[action](JSON.stringify({
data: data,
callback: callbackName
}));
});
}
// 使用async函数来调用sendMessageToNative,并等待原生代码的回复
// 业务请求(带验证码校验)回调函数
async function captchaVerifyCallback(captchaVerifyParam) {
// 1.调用sendMessageToNative方法获取验证结果
let result = {};
try {
console.log(captchaVerifyParam);
result = await sendMessageToNative('getVerifyResult', captchaVerifyParam);
console.log('安卓返回的验证结果:', result);
} catch (error) {
console.error('发生错误:', error);
// 错误处理/兼容逻辑
result = {
captchaVerifyResult: false,
bizResult: false,
};
}
// 如果是在App侧执行验证码是否通过/业务验证是否通过逻辑,则不需要下面的返回值,直接关闭H5即可
const verifyResult = {
captchaResult: result.captchaResult, // 验证码验证是否通过,boolean类型,必选
bizResult: result.bizReuslt, // 业务验证是否通过,boolean类型,可选;若为无业务验证结果的场景,bizResult可以为空
};
return verifyResult;
}
同时,参考如下示例修改Java代码,将验证结果返回给H5页面,并根据业务需求来决定在App侧或H5侧执行业务自定义提示逻辑:
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
public class testJsInterface {
private WebView webView;
// 构造函数,传入WebView对象
public testJsInterface(WebView webView) {
this.webView = webView;
}
// 通过JavaScriptInterface注解暴露给JavaScript的方法
@JavascriptInterface
public void getVerifyResult(String jsonString) {
try {
// 将JSON字符串转换为JSONObject
JSONObject jsonObject = new JSONObject(jsonString);
String captchaVerifyParam = jsonObject.getString("data");
String callbackName = jsonObject.getString("callback");
// 用captchaVerifyParam请求后端接口拿到请求结果
// JSONObject verifyResult = requestAPI(captchaVerifyParam);
JSONObject result = new JSONObject();
// 这里模拟一下返回结果
result.put("captchaResult", true);
result.put("bizResult", true);
String resultString = result.toString(); // result可以转换为一个JSON字符串,注意传给H5之后的数据格式转换
System.out.println(resultString);
// 处理完数据后,将结果回传给H5页面
// 这里需要确保操作在主线程(UI线程)中执行
webview.post(new Runnable() {
@Override
public void run() {
// 使用evaluateJavascript发送回调到H5页面
webview.evaluateJavascript("javascript:" + callbackName + "('" + escapeJavaScriptString(resultString) + "')", null);
// 根据result在App测来执行业务自定义提示逻辑,H5中的onBizResultCallback可以置为空函数
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
// 对JavaScript字符串进行转义,避免JavaScript注入问题
private String escapeJavaScriptString(String string) {
// 这是一个简单的转义示例。对于更复杂的情况,可能需要更有效的转义方法
return string.replace("'", "\\'").replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\\\"");
}
}
App接入Demo示例下载
关于安卓示例,更多详情,请参见安卓 Demo(Java)。
关于iOS示例,更多详情,请参见iOS Demo(Swift)。