Dùng WebView
để phân phối một ứng dụng web
hoặc trang web như một phần của ứng dụng khách. Lớp WebView
là một
phần mở rộng của lớp View
của Android để cho phép
bạn sẽ hiển thị các trang web trong bố cục hoạt động của mình. Số liệu này không bao gồm
của một trình duyệt web được phát triển hoàn chỉnh, chẳng hạn như các nút điều khiển điều hướng hoặc
thanh địa chỉ. Theo mặc định, tất cả những gì WebView
có thể làm là hiển thị một trang web.
WebView
có thể giúp bạn cung cấp thông tin trong ứng dụng mà bạn có thể cần
bản cập nhật mới, chẳng hạn như thoả thuận người dùng cuối hoặc hướng dẫn sử dụng. Trong ứng dụng Android,
bạn có thể tạo Activity
chứa
WebView
, rồi sử dụng bảng này để hiển thị tài liệu được lưu trữ trực tuyến.
WebView
cũng có thể trợ giúp khi ứng dụng của bạn cung cấp dữ liệu cho người dùng yêu cầu
kết nối Internet để truy xuất dữ liệu, chẳng hạn như email. Trong trường hợp này, bạn có thể
thấy rằng việc tạo WebView
trong ứng dụng Android cho thấy một trang web sẽ dễ dàng hơn
trang có tất cả dữ liệu người dùng, thay vì thực hiện yêu cầu mạng, thì
phân tích cú pháp dữ liệu và hiển thị dữ liệu đó trong bố cục Android. Thay vào đó, bạn có thể thiết kế
một trang web được thiết kế riêng cho các thiết bị chạy Android rồi triển khai
WebView
trong ứng dụng Android tải trang web.
Tài liệu này mô tả cách bắt đầu sử dụng WebView
và cách liên kết
JavaScript từ trang web của bạn đến mã phía máy khách trong ứng dụng Android của bạn, cách
xử lý thao tác điều hướng trang và cách quản lý cửa sổ khi sử dụng WebView
.
Tương thích với WebView trên các phiên bản Android cũ
Để sử dụng các tính năng mới hơn của WebView
trên thiết bị một cách an toàn, ứng dụng của bạn
đang chạy, hãy thêm AndroidX
Thư viện Webkit. Đây là một hình ảnh tĩnh
bạn có thể thêm vào ứng dụng của mình để sử dụng các API android.webkit
không
có sẵn cho các phiên bản nền tảng cũ hơn.
Thêm vào tệp build.gradle
như sau:
Kotlin
dependencies { implementation("androidx.webkit:webkit:1.8.0") }
Groovy
dependencies { implementation ("androidx.webkit:webkit:1.8.0") }
Khám phá WebView
ví dụ
trên GitHub để biết thêm chi tiết.
Thêm WebView vào ứng dụng
Để thêm WebView
vào ứng dụng, bạn có thể thêm phần tử <WebView>
vào
bố cục hoạt động hoặc đặt toàn bộ cửa sổ Activity
dưới dạng WebView
trong
onCreate()
.
Thêm WebView trong bố cục hoạt động
Để thêm WebView
vào ứng dụng trong bố cục, hãy thêm mã sau vào
tệp XML bố cục của hoạt động:
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" />
Để tải một trang web trong WebView
, hãy sử dụng
loadUrl()
, với tư cách là
như trong ví dụ sau:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.loadUrl("http://www.example.com")
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com");
Thêm một WebView trong onCreate()
Để thêm WebView
vào ứng dụng của bạn bằng phương thức onCreate()
của một hoạt động, hãy sử dụng
logic tương tự như sau:
Kotlin
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
Sau đó, tải trang:
Kotlin
myWebView.loadUrl("http://www.example.com")
Java
myWebView.loadUrl("https://www.example.com");
Hoặc tải URL từ một chuỗi HTML:
Kotlin
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. val unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING) myWebView.loadData(encodedHtml, "text/html", "base64")
Java
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. String unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING); myWebView.loadData(encodedHtml, "text/html", "base64");
Ứng dụng của bạn phải có quyền truy cập Internet. Để truy cập Internet, hãy yêu cầu
Quyền INTERNET
trong
tệp kê khai, như được thể hiện trong ví dụ sau:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
Bạn có thể tuỳ chỉnh WebView
bằng cách thực hiện thao tác bất kỳ sau đây:
- Bật tính năng hỗ trợ toàn màn hình bằng
WebChromeClient
. Lớp này cũng được gọi khiWebView
cần quyền thay đổi giao diện người dùng của ứng dụng lưu trữ, chẳng hạn như tạo hoặc đóng cửa sổ hoặc gửi hộp thoại JavaScript đến người dùng. Để tìm hiểu thêm về cách gỡ lỗi trong trường hợp này, hãy đọc bài viết Gỡ lỗi web . - Xử lý các sự kiện ảnh hưởng đến quá trình hiển thị nội dung, chẳng hạn như các lỗi về biểu mẫu
gửi hoặc điều hướng bằng cách sử dụng
WebViewClient
. Bạn cũng có thể sử dụng lớp con này để chặn việc tải URL. - Bật JavaScript bằng cách sửa đổi
WebSettings
. - Sử dụng JavaScript để truy cập vào các đối tượng khung Android mà bạn đã chèn
vào
WebView
.
Sử dụng JavaScript trong WebView
Nếu trang web bạn muốn tải trong WebView
sử dụng JavaScript, bạn phải
bật JavaScript cho WebView
của bạn. Sau khi bật JavaScript, bạn có thể
tạo giao diện giữa mã ứng dụng và mã JavaScript của bạn.
Bật JavaScript
Theo mặc định, JavaScript bị tắt trong WebView
. Bạn có thể bật tính năng này thông qua
Đã đính kèm WebSettings
vào WebView
của bạn. Truy xuất WebSettings
bằng
getSettings()
, sau đó bật
JavaScript với
setJavaScriptEnabled()
.
Hãy xem ví dụ sau:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.settings.javaScriptEnabled = true
Java
WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true);
WebSettings
cung cấp quyền truy cập vào nhiều chế độ cài đặt khác mà bạn có thể tìm thấy
hữu ích. Ví dụ: nếu bạn đang phát triển một ứng dụng web được thiết kế
dành riêng cho WebView
trong ứng dụng Android, thì bạn có thể xác định một thuộc tính tuỳ chỉnh
chuỗi tác nhân người dùng với
setUserAgentString()
,
thì hãy truy vấn tác nhân người dùng tuỳ chỉnh trong trang web của bạn để xác minh rằng
yêu cầu trang web là ứng dụng Android của bạn.
Liên kết mã JavaScript với mã Android
Khi phát triển một ứng dụng web được thiết kế riêng cho WebView
trong ứng dụng Android, bạn có thể tạo giao diện giữa mã JavaScript và
mã Android phía máy khách. Ví dụ: mã JavaScript có thể gọi một phương thức trong
mã Android của bạn để hiển thị Dialog
,
thay vì sử dụng hàm alert()
của JavaScript.
Để liên kết giao diện mới giữa JavaScript và mã Android, hãy gọi
addJavascriptInterface()
!
truyền vào đó một thực thể lớp để liên kết với JavaScript và tên giao diện
mà JavaScript của bạn có thể gọi để truy cập vào lớp này.
Ví dụ: bạn có thể thêm lớp sau đây vào ứng dụng Android:
Kotlin
/** Instantiate the interface and set the context. */ class WebAppInterface(private val mContext: Context) { /** Show a toast from the web page. */ @JavascriptInterface fun showToast(toast: String) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show() } }
Java
public class WebAppInterface { Context mContext; /** Instantiate the interface and set the context. */ WebAppInterface(Context c) { mContext = c; } /** Show a toast from the web page. */ @JavascriptInterface public void showToast(String toast) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); } }
Trong ví dụ này, lớp WebAppInterface
cho phép trang web tạo một
Toast
, sử dụng showToast()
.
Bạn có thể liên kết lớp này với JavaScript chạy trong WebView
bằng
addJavascriptInterface()
, như trong ví dụ sau:
Kotlin
val webView: WebView = findViewById(R.id.webview) webView.addJavascriptInterface(WebAppInterface(this), "Android")
Java
WebView webView = (WebView) findViewById(R.id.webview); webView.addJavascriptInterface(new WebAppInterface(this), "Android");
Thao tác này sẽ tạo ra một giao diện có tên là Android
cho JavaScript chạy trong
WebView
Tại thời điểm này, ứng dụng web của bạn có quyền truy cập vào
Lớp WebAppInterface
. Ví dụ: dưới đây là một số HTML và JavaScript
tạo một thông báo ngắn bằng giao diện mới khi người dùng nhấn vào một nút:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script>
Bạn không cần khởi chạy giao diện Android
từ JavaScript. Chiến lược phát hành đĩa đơn
WebView
tự động cung cấp thư viện này cho trang web của bạn. Vì vậy, khi một người dùng
nhấn vào nút này, hàm showAndroidToast()
sẽ sử dụng giao diện Android
để gọi phương thức WebAppInterface.showToast()
.
Xử lý thao tác điều hướng trang
Theo mặc định, khi người dùng nhấn vào một đường liên kết trên một trang web trong WebView
, Android
khởi chạy một ứng dụng xử lý URL. Thông thường, trình duyệt web mặc định sẽ mở ra và
tải URL đích. Tuy nhiên, bạn có thể ghi đè hành vi này cho
WebView
để các đường liên kết sẽ mở trong WebView
. Sau đó, bạn có thể cho phép người dùng
di chuyển lùi lại và tiến lên thông qua lịch sử trang web được duy trì
theo WebView
của bạn.
Để mở các đường liên kết mà người dùng nhấn vào, hãy cung cấp WebViewClient
cho WebView
của bạn
đang sử dụng
setWebViewClient()
.
Tất cả các đường liên kết mà người dùng nhấn vào đều tải trong WebView
. Nếu bạn muốn kiểm soát nhiều hơn đối với
khi đường liên kết được nhấp vào sẽ tải, hãy tạo WebViewClient
của riêng bạn để ghi đè
shouldOverrideUrlLoading()
. Ví dụ sau giả định rằng MyWebViewClient
là một lớp bên trong
trong tổng số Activity
.
Kotlin
private class MyWebViewClient : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { if (Uri.parse(url).host == "www.example.com") { // This is your website, so don't override. Let your WebView load // the page. return false } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { startActivity(this) } return true } }
Java
private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { if ("www.example.com".equals(request.getUrl().getHost())) { // This is your website, so don't override. Let your WebView load the // page. return false; } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); startActivity(intent); return true; } }
Sau đó, hãy tạo một thực thể của WebViewClient
mới này cho WebView
:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
Giờ đây, khi người dùng nhấn vào một đường liên kết, hệ thống sẽ gọi
Phương thức shouldOverrideUrlLoading()
để kiểm tra xem máy chủ lưu trữ URL có khớp với nhau hay không
miền cụ thể, như được xác định trong ví dụ trước. Nếu khớp, thì
phương thức sẽ trả về giá trị false và không ghi đè URL đang tải. Chiến dịch này cho phép
WebView
tải URL như bình thường. Nếu máy chủ lưu trữ URL không khớp, thì
Intent
được tạo để chạy chế độ mặc định
Activity
để xử lý URL. URL này chuyển sang trình duyệt web mặc định của người dùng.
Xử lý URL tuỳ chỉnh
WebView
áp dụng các quy định hạn chế khi yêu cầu tài nguyên và phân giải các đường liên kết
sử dụng lược đồ URL tùy chỉnh. Ví dụ: nếu bạn triển khai lệnh gọi lại như
shouldOverrideUrlLoading()
hoặc
shouldInterceptRequest()
,
thì WebView
chỉ gọi chúng đối với các URL hợp lệ.
Ví dụ: WebView
có thể không gọi phương thức shouldOverrideUrlLoading()
cho các đường liên kết như sau:
<a href="showProfile">Show Profile</a>
Google sẽ xử lý các URL không hợp lệ (như URL trong ví dụ trước)
không nhất quán trong WebView
, vì vậy bạn nên sử dụng URL được định dạng đúng.
Bạn có thể sử dụng lược đồ tuỳ chỉnh hoặc URL loại HTTPS cho miền mà tổ chức của bạn
.
Thay vì sử dụng một chuỗi đơn giản trong một đường liên kết, như trong ví dụ trước, bạn có thể hãy sử dụng lược đồ tuỳ chỉnh, chẳng hạn như:
<a href="example-app:showProfile">Show Profile</a>
Sau đó, bạn có thể xử lý URL này trong phương thức shouldOverrideUrlLoading()
như
sau:
Kotlin
// The URL scheme must be non-hierarchical, meaning no trailing slashes. const val APP_SCHEME = "example-app:" override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { return if (url?.startsWith(APP_SCHEME) == true) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8") respondToData(urlData) true } else { false } }
Java
// The URL scheme must be non-hierarchical, meaning no trailing slashes. private static final String APP_SCHEME = "example-app:"; @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith(APP_SCHEME)) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8"); respondToData(urlData); return true; } return false; }
API shouldOverrideUrlLoading()
chủ yếu dùng để khởi chạy ý định
cho các URL cụ thể. Khi triển khai thẻ này, hãy nhớ trả về false
cho URL
WebView
xử lý. Tuy nhiên, bạn không bị giới hạn ở việc khởi chạy ý định. Bạn có thể
thay thế ý định khởi chạy bằng bất kỳ hành vi tuỳ chỉnh nào trong mã trước đó
mẫu.
Di chuyển trong nhật ký trang web
Khi WebView
của bạn ghi đè URL đang tải, URL đó sẽ tự động tích luỹ một
lịch sử của các trang web đã truy cập. Bạn có thể điều hướng tiến và lùi thông qua
lịch sử với goBack()
và
goForward()
.
Ví dụ: sau đây là cách Activity
có thể sử dụng tính năng Quay lại của thiết bị
nút điều hướng lùi:
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { // Check whether the key event is the Back button and if there's history. if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) { myWebView.goBack() return true } // If it isn't the Back button or there isn't web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event) }
Java
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Check whether the key event is the Back button and if there's history. if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) { myWebView.goBack(); return true; } // If it isn't the Back button or there's no web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event); }
Nếu ứng dụng của bạn sử dụng AndroidX AppCompat
1.6.0 trở lên, bạn có thể đơn giản hoá
trích đoạn nội dung khác:
Kotlin
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack() } }
Java
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack(); } }
Phương thức canGoBack()
trả về true nếu có lịch sử trang web để người dùng truy cập. Tương tự, bạn
có thể sử dụng canGoForward()
để
kiểm tra xem có nhật ký chuyển tiếp hay không. Nếu không thực hiện bước kiểm tra này, thì
sau khi người dùng xem hết nhật ký, goBack()
và goForward()
sẽ
không có gì.
Xử lý các thay đổi về cấu hình thiết bị
Trong thời gian chạy, trạng thái hoạt động sẽ thay đổi khi cấu hình của thiết bị
các thay đổi, chẳng hạn như khi người dùng xoay thiết bị hoặc đóng trình chỉnh sửa phương thức nhập
(IME). Những thay đổi này khiến hoạt động của một đối tượng WebView
bị huỷ bỏ và một
hoạt động mới cần được tạo, việc này cũng sẽ tạo một đối tượng WebView
mới tải
URL của đối tượng bị huỷ bỏ. Để sửa đổi hành vi mặc định của hoạt động, bạn có thể
thay đổi cách xử lý các thay đổi về orientation
trong tệp kê khai. Để tìm hiểu thêm
về cách xử lý các thay đổi về cấu hình trong thời gian chạy, hãy đọc bài viết Xử lý cấu hình
thay đổi.
Quản lý cửa sổ
Theo mặc định, các yêu cầu mở cửa sổ mới sẽ bị bỏ qua. Điều này đúng cho dù
được mở bởi JavaScript hoặc bởi thuộc tính mục tiêu trong liên kết. Bạn có thể tuỳ chỉnh
WebChromeClient
để cung cấp hành vi của riêng bạn khi mở nhiều
.
Để giữ cho ứng dụng của bạn an toàn hơn, tốt nhất bạn nên ngăn chặn cửa sổ bật lên và cửa sổ mới
mở. Cách an toàn nhất để triển khai hành vi này là chuyển "true"
vào
setSupportMultipleWindows()
nhưng không ghi đè
onCreateWindow()
mà setSupportMultipleWindows()
phụ thuộc vào. Logic này ngăn chặn bất kỳ
sử dụng target="_blank"
trong liên kết của trang đó khi tải.