最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端使用阿里云圖形驗證碼并且與安卓進行交互實現(xiàn)方法

 更新時間:2025年12月02日 09:40:57   作者:巧克力芋泥包  
阿里云短信服務提供API/SDK和控制臺調(diào)用方式,支持驗證碼、通知、推廣等短信類型,下面這篇文章主要介紹了前端使用阿里云圖形驗證碼并且與安卓進行交互實現(xiàn)的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

最近安卓同事那邊沒辦法去用原生的圖形驗證碼;要前端寫個html內(nèi)嵌進去,下面是流程如何實現(xiàn)的:

流程如下

1.引入阿里云前端腳本 & 基礎配置 在<head> 里:

<script>
    window.AliyunCaptchaConfig = {
        region: "cn",
        prefix: "1fnzmt",
    };
</script>

<script src="https://o.alicdn.com/captcha-frontend/aliyunCaptcha/AliyunCaptcha.js"></script>

window.AliyunCaptchaConfig:阿里云驗證碼的全局配置 region: “cn”:中國大陸區(qū)域
prefix: “1fnzmt”:你在阿里云控制臺那邊分配的前綴
AliyunCaptcha.js:阿里云的前端驗證碼 SDK 腳本,加載后會在window 上掛 initAliyunCaptcha 之類的方法。

自己又定義了一個 CONFIG:

const CONFIG = {
    region: "cn",
    prefix: "1fnzmt",
    sceneId: "vjsqgp2k",
    mode: "popup",
    language: "cn",
    slideStyle: { width: 360, height: 40 },
    apiBaseURL: "http://39.96.184.160",
    endpoints: {
        captchaVerify: "/dev-api/android/sms/code"
    }
};

sceneId: 阿里云驗證碼具體場景 ID。
apiBaseURL + endpoints.captchaVerify:你自己后端的驗證碼驗證接口地址。

2.初始化阿里云驗證碼實例

CaptchaManager.init() 里:

window.initAliyunCaptcha({
    SceneId: CONFIG.sceneId,
    mode: CONFIG.mode,
    element: '#captcha-element',
    button: '#verify-btn',
    captchaVerifyCallback: this.captchaVerifyCallback.bind(this),
    onBizResultCallback: this.onBizResultCallback.bind(this),
    getInstance: (instance) => {
        this.captcha = instance;
        debugLog('驗證碼初始化成功');
    }
});

邏輯:

  • element: ‘#captcha-element’:驗證碼掛載在頁面中這個 div 上。
  • button: ‘#verify-btn’:點擊“開始驗證”按鈕時,彈出/觸發(fā)驗證碼。
  • captchaVerifyCallback:用戶通過驗證碼后,阿里云前端 SDK 會給你一個 captchaVerifyParam,然后會調(diào)用這個回調(diào)。
  • onBizResultCallback:你業(yè)務側驗證成功/失敗后,返回一個業(yè)務結果給前端,這個回調(diào)會被觸發(fā)。

3.驗證碼通過后,前端調(diào)用你后端接口

captchaVerifyCallback 的實現(xiàn):

async captchaVerifyCallback(captchaVerifyParam) {
    this.showStatus('驗證中...', 'loading');

    try {
        document.getElementById('verify-btn').disabled = true;

        // 1. 先去原生拿手機號(下面第二部分會講這個接口)
        const phoneNumber = await this.getPhoneNumber();
        debugLog('最終使用的手機號: ' + phoneNumber);

        // 2. 調(diào)用你后端的驗證接口(目前是 GET 請求)
        const result = await this.apiRequest(CONFIG.endpoints.captchaVerify, {
            phoneNumber: phoneNumber,
            captchaVerifyParam: captchaVerifyParam
        });

        debugLog('后端返回結果: ' + JSON.stringify(result));

        // 3. 按你的后端返回格式判斷是否成功
        const success = result && result.code === 200 && result.data === true;

        if (success) {
            this.showStatus('驗證成功!', 'success');
        } else {
            const msg = (result && result.msg) ? result.msg : '驗證失敗';
            this.showStatus(msg, 'error');
        }

        // 4. 返回給阿里云 SDK 一個統(tǒng)一結構
        return {
            captchaResult: success,
            bizResult: success
        };
    } catch (error) {
        debugLog('驗證失敗: ' + error.message);
        this.showStatus('驗證失敗: ' + error.message, 'error');
        return {
            captchaResult: false,
            bizResult: false
        };
    } finally {
        document.getElementById('verify-btn').disabled = false;
    }
}

調(diào)用后端的封裝在 apiRequest里:

async apiRequest(url, data) {
    // 1. 拼接完整 URL
    if (url.startsWith('http')) {
        fullUrl = url;
    } else if (url.startsWith('/')) {
        fullUrl = CONFIG.apiBaseURL + url;
    } else {
        fullUrl = CONFIG.apiBaseURL + '/' + url;
    }

    // 2. 把 data 轉(zhuǎn)成 query 參數(shù) ?phoneNumber=xxx&captchaVerifyParam=yyy
    const queryParams = new URLSearchParams();
    for (const key in data) {
        if (data[key] !== null && data[key] !== undefined) {
            queryParams.append(key, data[key]);
        }
    }
    ...

    const response = await fetch(fullUrl, {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json',
        }
    });

    const result = await response.json();
    ...
    return result;
}

總結這一塊:

前端通過 AliyunCaptcha.js 提供的 initAliyunCaptcha 接入阿里云驗證碼。
用戶操作 → 驗證碼通過 → 阿里云前端回調(diào) captchaVerifyCallback。
回調(diào)里先從安卓拿手機號,再調(diào)用你自己后端接口 /dev-api/android/sms/code。
后端返回 code=200 && data=true 視為驗證成功,再通過返回值告知阿里云 SDK 驗證結果。

跟安卓原生通訊的邏輯

與安卓約定的對象和方法

在 JS 這邊約定:

原生會在 window 上注入一個對象:window.testInterface。

你用的接口方法:

testInterface.getPhoneNumber(callbackName):安卓會拿到 callbackName,執(zhí)行完再在 JS 中調(diào)用 windowcallbackName 回傳結果。
testInterface.closeWebView():用于在業(yè)務成功時關閉 WebView。

這些是靠安卓那邊 WebView addJavascriptInterface 或 evaluateJavascript 實現(xiàn)的。

小結

阿里云連接邏輯: 通過 AliyunCaptcha.js + window.AliyunCaptchaConfig +initAliyunCaptcha 接入。 成功后在 captchaVerifyCallback 里拿到captchaVerifyParam。 再帶上手機號請求你自己后端http://39.96.184.160/dev-api/android/sms/code 進行業(yè)務驗證。 驗證結果再通過返回值以及
onBizResultCallback 和頁面交互。 與安卓通訊邏輯: 瀏覽器端默認認為安卓會注入
window.testInterface。 通過 NativeInterfaceManager 輪詢和回調(diào)機制確定接口是否可用。 通過
sendMessageToNative(action, callbackName) 把一個回調(diào)函數(shù)名給安卓,安卓執(zhí)行完再回調(diào)
windowcallbackName。 當前主要用到:
testInterface.getPhoneNumber(callbackName) → 獲取手機號
testInterface.closeWebView() → 業(yè)務成功后關閉 WebView 如果原生沒準備好或調(diào)用失敗,就用模擬數(shù)據(jù)
13400134000,頁面上也會顯示“模擬數(shù)據(jù)”。

完整代碼:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>圖形驗證碼驗證</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .captcha-container {
            width: 100%;
            max-width: 450px;
        }

        .captcha-form {
            background: white;
            padding: 30px;
            border-radius: 12px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            text-align: center;
        }

        .captcha-form h2 {
            color: #333;
            margin-bottom: 8px;
            font-weight: 600;
        }

        .description {
            color: #666;
            margin-bottom: 24px;
            font-size: 14px;
            line-height: 1.5;
        }

        .captcha-element {
            margin: 20px 0;
            min-height: 80px;
            display: flex;
            justify-content: center;
            align-items: center;
            border: 2px dashed #e0e0e0;
            border-radius: 8px;
            padding: 15px;
            background: #fafafa;
        }

        .verify-btn {
            width: 100%;
            padding: 14px;
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 16px;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.3s ease;
            margin-bottom: 15px;
        }

        .verify-btn:hover:not(:disabled) {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }

        .verify-btn:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        .status-message {
            margin: 15px 0;
            padding: 10px;
            border-radius: 4px;
            font-size: 14px;
            min-height: 20px;
        }

        .status-success {
            background: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }

        .status-error {
            background: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }

        .status-loading {
            background: #d1ecf1;
            color: #0c5460;
            border: 1px solid #bee5eb;
        }

        .server-info {
            background: rgba(0, 0, 0, 0.05);
            padding: 10px;
            border-radius: 5px;
            margin-top: 15px;
            font-size: 12px;
            color: #666;
            line-height: 1.5;
        }

        .debug-info {
            background: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 5px;
            padding: 10px;
            margin-top: 15px;
            font-size: 12px;
            text-align: left;
            max-height: 200px;
            overflow-y: auto;
        }

        .debug-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 8px;
        }

        .debug-controls button {
            background: #6c757d;
            color: white;
            border: none;
            padding: 4px 8px;
            border-radius: 3px;
            font-size: 10px;
            cursor: pointer;
            margin-left: 5px;
        }

        .debug-controls button:hover {
            background: #5a6268;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .loading {
            display: inline-block;
            width: 16px;
            height: 16px;
            border: 2px solid #f3f3f3;
            border-top: 2px solid #667eea;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin-right: 8px;
            vertical-align: middle;
        }

        .interface-status {
            padding: 8px;
            border-radius: 4px;
            margin: 10px 0;
            font-weight: bold;
        }

        .interface-ready {
            background: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }

        .interface-waiting {
            background: #fff3cd;
            color: #856404;
            border: 1px solid #ffeaa7;
        }

        .interface-missing {
            background: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }

        .phone-info {
            background: #e7f3ff;
            color: #0066cc;
            border: 1px solid #b3d9ff;
            padding: 8px;
            border-radius: 4px;
            margin: 10px 0;
            font-size: 14px;
        }

        .phone-number {
            font-weight: bold;
            color: #004085;
        }
    </style>

    <!-- 阿里云驗證碼配置 -->
    <script>
        window.AliyunCaptchaConfig = {
            region: "cn",
            prefix: "1fnzmt",
        };
    </script>

    <!-- 引入阿里云驗證碼JS -->
    <script src="https://o.alicdn.com/captcha-frontend/aliyunCaptcha/AliyunCaptcha.js"></script>
    
    <!-- 引入vConsole用于移動端調(diào)試 -->
    <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
    <script>
        // 初始化vConsole
        var vConsole = new VConsole();
        console.log('? vConsole已加載,可以在移動端查看調(diào)試信息');
    </script>
</head>

<body>
    <div class="captcha-container">
        <div class="captcha-form">
            <h2>安全驗證</h2>
            <p class="description">請完成驗證以繼續(xù)操作</p>

            <!-- 接口狀態(tài)顯示 -->
            <div id="interface-status" class="interface-status interface-waiting">
                正在檢測原生接口...
            </div>

            <!-- 手機號信息顯示 -->
            <div id="phone-info" class="phone-info">
                當前手機號: <span id="current-phone" class="phone-number">等待獲取中...</span>
            </div>

            <!-- 驗證碼容器 -->
            <div id="captcha-element" class="captcha-element"></div>

            <!-- 驗證狀態(tài) -->
            <div id="status-message" class="status-message"></div>

            <button id="verify-btn" class="verify-btn">開始驗證</button>

            <div class="server-info">
                服務器地址: 192.168.5.59:5500

                當前時間: <span id="current-time"></span>
            </div>

            <!-- 調(diào)試信息 -->
            <div class="debug-info">
                <div class="debug-header">
                    <h4>調(diào)試信息:</h4>
                    <div class="debug-controls">
                        <button id="clear-log">清空日志</button>
                        <button id="test-interface">測試接口</button>
                    </div>
                </div>
                <div id="debug-log"></div>
            </div>
        </div>
    </div>

    <script>
        // 調(diào)試日志
        function debugLog(message) {
            const logElement = document.getElementById('debug-log');
            const timestamp = new Date().toLocaleTimeString();
            logElement.innerHTML += `[${timestamp}] ${message}
`;
            console.log(message);
            
            // 自動滾動到底部
            logElement.scrollTop = logElement.scrollHeight;
        }

        // 顯示當前時間
        function updateTime() {
            document.getElementById('current-time').textContent = new Date().toLocaleString();
        }
        setInterval(updateTime, 1000);
        updateTime();

        // 配置參數(shù)
        const CONFIG = {
            region: "cn",
            prefix: "1fnzmt",
            sceneId: "vjsqgp2k",
            mode: "popup",
            language: "cn",
            slideStyle: {
                width: 360,
                height: 40
            },
            apiBaseURL: "http://39.96.184.160",
            endpoints: {
                captchaVerify: "/dev-api/android/sms/code"
            }
        };

        // 原生接口管理器
        class NativeInterfaceManager {
            constructor() {
                this.isReady = false;
                this.interfaceName = 'testInterface';
                this.readyCallbacks = [];
                this.retryCount = 0;
                this.maxRetries = 100; // 延長到10秒
                this.checkInterval = null;
                this.init();
            }
            
            init() {
                debugLog('初始化原生接口管理器');
                debugLog('當前window對象的屬性: ' + Object.keys(window).filter(k => k.includes('test') || k.includes('Interface')).join(', '));
                
                // 立即檢測一次
                if (this.checkInterface()) {
                    return;
                }
                
                // 延遲啟動檢測,給Android更多注入時間
                setTimeout(() => {
                    debugLog('開始定期檢測原生接口...');
                    this.startPeriodicCheck();
                }, 500);
            }
            
            startPeriodicCheck() {
                this.checkInterval = setInterval(() => {
                    debugLog(`檢測原生接口 (${this.retryCount + 1}/${this.maxRetries})`);
                    
                    if (this.checkInterface() || this.retryCount >= this.maxRetries) {
                        clearInterval(this.checkInterval);
                        if (!this.isReady) {
                            debugLog('? 達到最大重試次數(shù),原生接口仍未就緒');
                            this.showInterfaceStatus('missing', '原生接口未就緒,使用模擬模式');
                        }
                    }
                    this.retryCount++;
                }, 100);
            }
            
            checkInterface() {
                if (window[this.interfaceName]) {
                    this.isReady = true;
                    debugLog('? 原生接口檢測成功');
                    this.showInterfaceStatus('ready', '原生接口已就緒');
                    
                    // 執(zhí)行所有等待的回調(diào)
                    this.readyCallbacks.forEach(callback => callback(window[this.interfaceName]));
                    this.readyCallbacks = [];
                    
                    return true;
                }
                return false;
            }
            
            onReady(callback) {
                if (this.isReady) {
                    callback(window[this.interfaceName]);
                } else {
                    this.readyCallbacks.push(callback);
                }
            }
            
            async call(method, data) {
                return new Promise((resolve, reject) => {
                    this.onReady(async (interfaceObj) => {
                        try {
                            const result = await this.sendMessageToNative(method, data, interfaceObj);
                            resolve(result);
                        } catch (error) {
                            reject(error);
                        }
                    });
                    
                    // 如果接口未就緒,直接使用模擬數(shù)據(jù)
                    if (!this.isReady) {
                        debugLog('接口未就緒,使用模擬數(shù)據(jù)');
                        setTimeout(() => {
                            this.simulateNativeResponse(method).then(resolve);
                        }, 500);
                    }
                });
            }
            
            // async sendMessageToNative(action, data, interfaceObj) {
            //     return new Promise((resolve, reject) => {
            //         const callbackName = 'cb_' + Math.random().toString(36).substring(2);
                    
            //         debugLog(`發(fā)送消息給原生代碼,action: ${action}, callback: ${callbackName}`);
                    
            //         window[callbackName] = (response) => {
            //             debugLog('安卓返回的驗證結果: ' + response);
                        
            //             try {
            //                 const result = typeof response === 'string' ? JSON.parse(response) : response;
            //                 resolve(result);
            //             } catch (error) {
            //                 debugLog('解析安卓返回結果失敗: ' + error);
            //                 reject(error);
            //             }
                        
            //             delete window[callbackName];
            //         };
                    
            //         const timeoutId = setTimeout(() => {
            //             debugLog('調(diào)用原生方法超時');
            //             delete window[callbackName];
            //             this.simulateNativeResponse(action).then(resolve);
            //         }, 5000);
                    
            //         if (interfaceObj && interfaceObj[action]) {
            //             try {
            //                 // 直接傳遞回調(diào)函數(shù)名給安卓端
            //                 interfaceObj[action](callbackName);
            //                 clearTimeout(timeoutId);
            //             } catch (error) {
            //                 debugLog('調(diào)用原生方法失敗: ' + error);
            //                 clearTimeout(timeoutId);
            //                 this.simulateNativeResponse(action).then(resolve);
            //             }
            //         } else {
            //             debugLog(`接口 ${this.interfaceName}.${action} 不存在,使用模擬數(shù)據(jù)`);
            //             clearTimeout(timeoutId);
            //             this.simulateNativeResponse(action).then(resolve);
            //         }
            //     });
            // }

            // 修改sendMessageToNative方法
async sendMessageToNative(action, data, interfaceObj) {
    return new Promise((resolve, reject) => {
        const callbackName = 'cb_' + Math.random().toString(36).substring(2);
        
        debugLog(`發(fā)送消息給原生代碼,action: ${action}, callback: ${callbackName}`);
        
        window[callbackName] = (response) => {
            debugLog('安卓返回的驗證結果: ' + response);
            
            try {
                const result = typeof response === 'string' ? JSON.parse(response) : response;
                resolve(result);
            } catch (error) {
                debugLog('解析安卓返回結果失敗: ' + error);
                reject(error);
            }
            
            delete window[callbackName];
        };
        
        const timeoutId = setTimeout(() => {
            debugLog('調(diào)用原生方法超時');
            delete window[callbackName];
            this.simulateNativeResponse(action).then(resolve);
        }, 5000);
        
        if (interfaceObj && interfaceObj[action]) {
            try {
                // 直接傳遞回調(diào)函數(shù)名給安卓端
                interfaceObj[action](callbackName);
                clearTimeout(timeoutId);
            } catch (error) {
                debugLog('調(diào)用原生方法失敗: ' + error);
                clearTimeout(timeoutId);
                this.simulateNativeResponse(action).then(resolve);
            }
        } else {
            debugLog(`接口 ${this.interfaceName}.${action} 不存在,使用模擬數(shù)據(jù)`);
            clearTimeout(timeoutId);
            this.simulateNativeResponse(action).then(resolve);
        }
    });
}
            
            simulateNativeResponse(action) {
                return new Promise((resolve) => {
                    setTimeout(() => {
                        let mockData = {};
                        if (action === 'getPhoneNumber') {
                            mockData = {
                                phoneNumber: '13400134000',
                                success: true
                            };
                        }
                        debugLog(`模擬響應: ${JSON.stringify(mockData)}`);
                        resolve(mockData);
                    }, 500);
                });
            }
            
            showInterfaceStatus(status, message) {
                const element = document.getElementById('interface-status');
                element.textContent = message;
                element.className = `interface-status interface-${status}`;
            }
            
            // 測試接口
            async test() {
                debugLog('=== 測試原生接口 ===');
                
                if (this.isReady) {
                    debugLog('? testInterface對象存在');
                    debugLog('testInterface方法: ' + Object.keys(window.testInterface).join(', '));
                    
                    if (window.testInterface.getPhoneNumber) {
                        debugLog('? getPhoneNumber方法存在');
                        
                        try {
                            const result = await this.call('getPhoneNumber', {});
                            debugLog('原生接口測試成功: ' + JSON.stringify(result));
                        } catch (error) {
                            debugLog('原生接口測試失敗: ' + error);
                        }
                    } else {
                        debugLog('? getPhoneNumber方法不存在');
                    }
                } else {
                    debugLog('? testInterface對象不存在');
                }
            }
        }

        // 驗證碼管理
        class CaptchaManager {
            constructor() {
                this.captcha = null;
                this.nativeInterface = new NativeInterfaceManager();
                this.currentPhoneNumber = null;
                this.init();
            }

            init() {
                try {
                    debugLog('開始初始化阿里云驗證碼');
                    
                    window.initAliyunCaptcha({
                        SceneId: CONFIG.sceneId,
                        mode: CONFIG.mode,
                        element: '#captcha-element',
                        button: '#verify-btn',
                        captchaVerifyCallback: this.captchaVerifyCallback.bind(this),
                        onBizResultCallback: this.onBizResultCallback.bind(this),
                        getInstance: (instance) => {
                            this.captcha = instance;
                            debugLog('驗證碼初始化成功');
                        }
                    });
                } catch (error) {
                    debugLog('驗證碼初始化失敗: ' + error.message);
                }
            }

            // 獲取手機號 - 使用原生接口管理器
            async getPhoneNumber() {
                debugLog('開始獲取手機號');
                
                try {
                    const result = await this.nativeInterface.call('getPhoneNumber', {});
                    
                    if (result && result.phoneNumber) {
                        debugLog('成功獲取手機號: ' + result.phoneNumber);
                        this.updatePhoneDisplay(result.phoneNumber, true);
                        return result.phoneNumber;
                    } else {
                        debugLog('獲取手機號失敗,使用默認值');
                        this.updatePhoneDisplay('13400134000', false);
                        return '13400134000';
                    }
                } catch (error) {
                    debugLog('獲取手機號異常: ' + error.message);
                    this.updatePhoneDisplay('13400134000', false);
                    return '13400134000';
                }
            }

            // 更新手機號顯示
            updatePhoneDisplay(phoneNumber, isReal) {
                this.currentPhoneNumber = phoneNumber;
                const phoneElement = document.getElementById('current-phone');
                
                if (isReal) {
                    phoneElement.textContent = phoneNumber;
                    phoneElement.style.color = '#155724';
                    document.getElementById('phone-info').style.background = '#d4edda';
                    document.getElementById('phone-info').style.borderColor = '#c3e6cb';
                    document.getElementById('phone-info').style.color = '#155724';
                } else {
                    phoneElement.textContent = phoneNumber + ' (模擬數(shù)據(jù))';
                    phoneElement.style.color = '#721c24';
                    document.getElementById('phone-info').style.background = '#f8d7da';
                    document.getElementById('phone-info').style.borderColor = '#f5c6cb';
                    document.getElementById('phone-info').style.color = '#721c24';
                }
                
                debugLog(`當前使用的手機號: ${phoneNumber} ${isReal ? '(真實數(shù)據(jù))' : '(模擬數(shù)據(jù))'}`);
            }

            // API請求封裝 - 修改為GET請求
            async apiRequest(url, data) {
                try {
                    let fullUrl;
                    if (url.startsWith('http')) {
                        fullUrl = url;
                    } else if (url.startsWith('/')) {
                        fullUrl = CONFIG.apiBaseURL + url;
                    } else {
                        fullUrl = CONFIG.apiBaseURL + '/' + url;
                    }

                    // 構建查詢字符串
                    const queryParams = new URLSearchParams();
                    for (const key in data) {
                        if (data[key] !== null && data[key] !== undefined) {
                            queryParams.append(key, data[key]);
                        }
                    }
                    
                    const queryString = queryParams.toString();
                    if (queryString) {
                        fullUrl += (fullUrl.includes('?') ? '&' : '?') + queryString;
                    }

                    debugLog('請求URL: ' + fullUrl);
                    debugLog('請求數(shù)據(jù): ' + JSON.stringify(data));

                    const response = await fetch(fullUrl, {
                        method: 'GET',
                        headers: {
                            'Content-Type': 'application/json',
                        }
                    });

                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }

                    const result = await response.json();
                    debugLog('響應結果: ' + JSON.stringify(result));
                    return result;

                } catch (error) {
                    debugLog('API請求失敗: ' + error.message);
                    throw error;
                }
            }

            // 驗證回調(diào)
            async captchaVerifyCallback(captchaVerifyParam) {
                this.showStatus('驗證中...', 'loading');

                try {
                    // 禁用驗證按鈕
                    document.getElementById('verify-btn').disabled = true;
                    
                    // 使用原生接口管理器獲取手機號
                    const phoneNumber = await this.getPhoneNumber();
                    debugLog('最終使用的手機號: ' + phoneNumber);

                    // 調(diào)用后端API - 使用GET請求
                    const result = await this.apiRequest(CONFIG.endpoints.captchaVerify, {
                        phoneNumber: phoneNumber,
                        captchaVerifyParam: captchaVerifyParam
                    });

                    debugLog('后端返回結果: ' + JSON.stringify(result));

                    // 根據(jù)后端 code 和 data 判斷是否驗證成功
                    const success = result && result.code === 200 && result.data === true;

                    if (success) {
                        this.showStatus('驗證成功!', 'success');
                    } else {
                        const msg = (result && result.msg) ? result.msg : '驗證失敗';
                        this.showStatus(msg, 'error');
                    }

                    // 按照阿里云要求返回結構
                    return {
                        captchaResult: success,
                        bizResult: success
                    };
                } catch (error) {
                    debugLog('驗證失敗: ' + error.message);
                    this.showStatus('驗證失敗: ' + error.message, 'error');
                    return {
                        captchaResult: false,
                        bizResult: false
                    };
                } finally {
                    document.getElementById('verify-btn').disabled = false;
                }
            }

            // 業(yè)務回調(diào)
            onBizResultCallback(bizResult) {
                if (bizResult) {
                    this.showStatus('驗證成功!', 'success');

                    // 調(diào)用安卓關閉 WebView
                    try {
                        if (window.testInterface && typeof window.testInterface.closeWebView === 'function') {
                            debugLog('調(diào)用安卓 closeWebView 方法關閉頁面');
                            window.testInterface.closeWebView();
                        } else {
                            debugLog('未找到 testInterface.closeWebView 方法');
                        }
                    } catch (e) {
                        debugLog('調(diào)用安卓 closeWebView 出錯: ' + e);
                    }

                    setTimeout(() => {
                        if (window.onCaptchaSuccess) {
                            window.onCaptchaSuccess();
                        }
                    }, 1000);
                } else {
                    this.showStatus('驗證失敗,請重試', 'error');
                }
            }

            showStatus(message, type) {
                const element = document.getElementById('status-message');
                element.textContent = message;
                element.className = `status-message status-${type}`;

                if (type === 'loading') {
                    element.innerHTML = `<span class="loading"></span>${message}`;
                }
            }
        }

        // 頁面加載后初始化
        document.addEventListener('DOMContentLoaded', () => {
            debugLog('頁面加載完成,開始初始化驗證碼');
            window.captchaManager = new CaptchaManager();
            
            // 初始化調(diào)試控件
            document.getElementById('clear-log').addEventListener('click', () => {
                document.getElementById('debug-log').innerHTML = '';
                debugLog('日志已清空');
            });
            
            document.getElementById('test-interface').addEventListener('click', () => {
                window.captchaManager.nativeInterface.test();
            });
        });

        // 成功回調(diào)
        window.onCaptchaSuccess = function () {
            debugLog('驗證碼驗證成功');
            alert('驗證成功!');
        };

        // 添加安卓端回調(diào)通知 - 增強版
        window.onNativeInterfaceReady = function() {
            debugLog('?? 收到安卓端通知:原生接口已就緒');
            if (window.captchaManager && window.captchaManager.nativeInterface) {
                // 強制重新檢測
                window.captchaManager.nativeInterface.isReady = false;
                if (window.captchaManager.nativeInterface.checkInterface()) {
                    // 停止定期檢測
                    if (window.captchaManager.nativeInterface.checkInterval) {
                        clearInterval(window.captchaManager.nativeInterface.checkInterval);
                    }
                }
            }
        };
        
        // 全局暴露檢測方法,供Android主動調(diào)用
        window.forceCheckInterface = function() {
            debugLog('?? Android主動觸發(fā)接口檢測');
            if (window.captchaManager && window.captchaManager.nativeInterface) {
                return window.captchaManager.nativeInterface.checkInterface();
            }
            return false;
        };

        // 延遲測試原生接口
        setTimeout(() => {
            debugLog('開始測試原生接口');
            if (window.captchaManager && window.captchaManager.nativeInterface) {
                window.captchaManager.nativeInterface.test();
            }
        }, 3000);
    </script>
</body>
</html>

總結 

到此這篇關于前端使用阿里云圖形驗證碼并且與安卓進行交互實現(xiàn)方法的文章就介紹到這了,更多相關前端使用阿里云圖形驗證碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

大荔县| 乐亭县| 太仓市| 塔河县| 大渡口区| 如皋市| 岳阳市| 类乌齐县| 湘西| 探索| 伊宁县| 铁岭市| 建平县| 桂阳县| 西峡县| 昌乐县| 乌兰浩特市| 肃北| 宜良县| 璧山县| 开原市| 巴中市| 玉树县| 霍邱县| 东源县| 巴楚县| 长宁区| 海南省| 沙雅县| 汤阴县| 乐山市| 永和县| 长春市| 霍邱县| 金湖县| 洛隆县| 灵武市| 合山市| 靖西县| 泾川县| 隆尧县|