首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Android WebViewClient 處理 URL 跳轉攔截與自定義 Scheme 完整指南

     編輯:Java 相關知識

WebView 是 Android 嵌入網頁的核心元件。本文深入解析 WebViewClient 如何攔截 URL 跳轉、處理自定義 Scheme(如 myapp://)、配合 shouldOverrideUrlLoading() 實現原生頁面跳轉、JS 交互與安全防護,附完整最佳實踐程式碼。

一、核心 API:shouldOverrideUrlLoading()

此方法在 WebView 即將載入新 URL 時回調,**回傳 true 表示攔截並自行處理,false 交由 WebView 繼續載入**。

webView.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        String url = request.getUrl().toString();
        return handleUrl(url);
    }

    // 相容 API 23 以下
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return handleUrl(url);
    }

    private boolean handleUrl(String url) {
        if (url.startsWith("myapp://")) {
            handleCustomScheme(url);
            return true; // 攔截
        }
        if (url.startsWith("tel:") || url.startsWith("mailto:")) {
            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
            return true;
        }
        // 其餘 http/https 讓 WebView 自行載入
        return false;
    }
});

二、自定義 Scheme 協定設計與解析

定義協定格式:myapp://action?param1=value1¶m2=value2

private void handleCustomScheme(String url) {
    Uri uri = Uri.parse(url);
    String action = uri.getHost(); // action 部分
    String param1 = uri.getQueryParameter("param1");

    switch (action) {
        case "openDetail":
            String id = uri.getQueryParameter("id");
            startActivity(new Intent(this, DetailActivity.class).putExtra("id", id));
            break;
        case "login":
            startActivity(new Intent(this, LoginActivity.class));
            break;
        case "pay":
            // 唤起支付流程
            break;
        default:
            Log.w(TAG, "未知 Scheme action: " + action);
    }
}

三、AndroidManifest 註冊 Scheme(可選,支援外部瀏覽器喚起 App)

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="myapp" android:host="openDetail" />
    </intent-filter>
</activity>

四、安全防護:防止任意 URL 載入與 XSS

  • 白名單機制: 僅允許特定域名載入,其餘攔截並彈出原生瀏覽器。
  • 檢查 URL 來源: 在 onPageStarted() 記錄主框架 URL,防止 iframe 注入惡意跳轉。
  • 禁用危險設定: setAllowFileAccess(false)、setAllowUniversalAccessFromFileURLs(false)。
  • JS 交互僅暴露必要介面: 使用 @JavascriptInterface 並針對 Android 4.2+ 加上註解。

五、完整最佳實踐類別

public class SafeWebViewClient extends WebViewClient {
    private static final Set<String> ALLOWED_DOMAINS = Set.of("example.com", "api.example.com");
    private final Context context;

    public SafeWebViewClient(Context context) { this.context = context; }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        String url = request.getUrl().toString();
        return handleNavigation(url);
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return handleNavigation(url);
    }

    private boolean handleNavigation(String url) {
        // 1. 自定義 Scheme
        if (url.startsWith("myapp://")) { handleCustomScheme(url); return true; }
        // 2. 系統 Scheme
        if (url.startsWith("tel:") || url.startsWith("mailto:") || url.startsWith("intent:")) {
            try { context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); } catch (Exception ignored) {}
            return true;
        }
        // 3. 域名白名單
        Uri uri = Uri.parse(url);
        if (!ALLOWED_DOMAINS.contains(uri.getHost())) {
            // 非白名單域名,用外部瀏覽器開啟
            context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
            return true;
        }
        // 4. 允許 WebView 載入
        return false;
    }

    private void handleCustomScheme(String url) { /* 同上 */ }

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        // 生產環境嚴禁 handler.proceed(),應顯示錯誤頁或取消載入
        handler.cancel();
        showSslErrorDialog();
    }
}

六、常見坑與解決方案

問題原因解決
shouldOverrideUrlLoading 不觸發未設定 WebViewClient 或 API 版本不匹配同時覆寫兩個版本的方法
頁面跳轉後無法返回未將歷史記錄加入 WebView攔截前呼叫 view.loadUrl(url) 而非 startActivity
JS 無法呼叫原生未加 @JavascriptInterface 或 ProGuard 混淆加註解 + keep 規則
SSL 錯誤頁面空白onReceivedSslError 預設取消載入實作自定義錯誤頁或引導用戶

掌握 WebViewClient 的跳轉攔截機制,能構建安全、流暢的混合式 App 體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved