文档

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示例下载

  • 本页导读
文档反馈