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)。