Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách hỗ trợ WebView đa cửa sổ (multiple windows) Android

Giới thiệu

Hướng dẫn này trình bày cách bật hỗ trợ đa cửa sổ (multiple windows) cho WebView Android, cho phép xử lý các liên kết target="_blank", window.open(), hoặc popup mới.

Các bước thực hiện

Bước 1: Tạo dự án mới

Tạo dự án Android Studio: File → New Project.

Bước 2: Layout activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

Bước 3: MainActivity.java

package com.example.myapplication;

import android.os.Build;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.app.ProgressDialog;

public class MainActivity extends AppCompatActivity {

    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Đang tải dữ liệu...");
        progressDialog.setCancelable(false);

        webView = findViewById(R.id.web_view);
        webView.requestFocus();
        
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        
        // QUAN TRỌNG: Bật hỗ trợ đa cửa sổ
        webSettings.setSupportMultipleWindows(true);
        
        // Cần thiết cho window.open() hoạt động
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        
        // Tùy chọn: cho phép zoom
        webSettings.setBuiltInZoomControls(true);
        webSettings.setDisplayZoomControls(false);

        webView.loadUrl("https://www.tutorialspoint.com/");

        // WebChromeClient BẮT BUỘC để xử lý cửa sổ mới
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                if (newProgress < 100) {
                    progressDialog.show();
                }
                if (newProgress == 100) {
                    progressDialog.dismiss();
                }
            }

            // Xử lý window.open() / target="_blank"
            @Override
            public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
                // Tạo WebView mới cho cửa sổ con
                WebView newWebView = new WebView(MainActivity.this);
                newWebView.getSettings().setJavaScriptEnabled(true);
                newWebView.getSettings().setSupportMultipleWindows(true);
                newWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
                
                // Thêm vào view hierarchy (ví dụ: Dialog, Fragment mới, hoặc Tab mới)
                // Ở đây demo đơn giản: load vào WebView hiện tại
                webView.removeView(newWebView); // Tránh leak
                WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
                transport.setWebView(newWebView);
                resultMsg.sendToTarget();
                
                return true;
            }

            // Đóng cửa sổ
            @Override
            public void onCloseWindow(WebView window) {
                super.onCloseWindow(window);
                // Xử lý đóng window con nếu cần
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (webView != null) {
            webView.destroy();
        }
    }
}

Bước 4: AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                

Giải thích cơ chế Multiple Windows

Luồng xử lý khi gặp target="_blank" hoặc window.open()

  1. JavaScript gọi window.open() hoặc user click link target="_blank"
  2. WebView gọi WebChromeClient.onCreateWindow()
  3. App tạo WebView mới, cấu hình settings
  4. App gán WebView mới vào WebView.WebViewTransport từ resultMsg.obj
  5. Gọi resultMsg.sendToTarget() để WebView gốc tiếp tục load URL trong WebView mới

Các cách hiển thị cửa sổ mới

CáchMô tảPhức tạp
Load trong WebView gốcThay thế nội dung hiện tại (đơn giản nhất)Thấp
Dialog/PopupHiển thị WebView mới trong DialogTrung bình
Tab LayoutMỗi window = 1 Tab (như trình duyệt)Cao
Activity mớiMở Activity mới chứa WebViewTrung bình

Ví dụ: Mở trong Dialog

@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
    WebView newWebView = new WebView(MainActivity.this);
    newWebView.getSettings().setJavaScriptEnabled(true);
    newWebView.getSettings().setSupportMultipleWindows(true);
    
    // Tạo Dialog chứa WebView mới
    Dialog dialog = new Dialog(MainActivity.this);
    dialog.setContentView(newWebView);
    dialog.setTitle("Cửa sổ mới");
    dialog.show();
    
    WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
    transport.setWebView(newWebView);
    resultMsg.sendToTarget();
    
    // Xử lý đóng dialog
    newWebView.setWebChromeClient(new WebChromeClient() {
        @Override
        public void onCloseWindow(WebView window) {
            dialog.dismiss();
        }
    });
    
    return true;
}

Lưu ý quan trọng

  • setSupportMultipleWindows(true) + setJavaScriptCanOpenWindowsAutomatically(true) - CẢ HAI đều cần.
  • Phải implement WebChromeClient.onCreateWindow() - nếu không, window.open() sẽ không hoạt động.
  • Cần quản lý vòng đời WebView con (destroy khi không dùng) để tránh memory leak.
  • Từ Android 10+, có thể cần xử lý quyền POPUP_WINDOW hoặc SYSTEM_ALERT_WINDOW cho dialog.