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()
- JavaScript gọi
window.open()hoặc user click linktarget="_blank" - WebView gọi
WebChromeClient.onCreateWindow() - App tạo
WebViewmới, cấu hình settings - App gán WebView mới vào
WebView.WebViewTransporttừresultMsg.obj - 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ách | Mô tả | Phức tạp |
|---|---|---|
| Load trong WebView gốc | Thay thế nội dung hiện tại (đơn giản nhất) | Thấp |
| Dialog/Popup | Hiển thị WebView mới trong Dialog | Trung bình |
| Tab Layout | Mỗi window = 1 Tab (như trình duyệt) | Cao |
| Activity mới | Mở Activity mới chứa WebView | Trung 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.