Bạn có thể cung cấp nội dung dựa trên nền tảng web (chẳng hạn như HTML, JavaScript và CSS—để ứng dụng của bạn sử dụng và bạn biên dịch tĩnh thành ứng dụng thay vì hơn là tìm nạp qua Internet.
Nội dung trong ứng dụng không yêu cầu truy cập Internet hay tiêu tốn băng thông của người dùng. Nếu
nội dung chỉ được thiết kế riêng cho WebView
, tức là nội dung đó
phụ thuộc vào việc giao tiếp với một ứng dụng gốc—thì người dùng không thể vô tình
hãy tải tệp đó trên trình duyệt web.
Tuy nhiên, nội dung trong ứng dụng có một số hạn chế. Cập nhật nội dung dựa trên nền tảng web yêu cầu vận chuyển một bản cập nhật ứng dụng mới và có khả năng sản phẩm không khớp giữa nội dung trên trang web và nội dung trong ứng dụng trên thiết bị. người dùng có phiên bản ứng dụng lỗi thời.
WebViewAssetLoader
WebViewAssetLoader
là một
tải nội dung trong ứng dụng theo cách linh hoạt và hiệu quả
WebView
. Lớp này hỗ trợ
sau:
- Tải nội dung bằng URL HTTP(S) để có khả năng tương thích với cùng nguồn gốc .
- Tải các tài nguyên phụ như JavaScript, CSS, hình ảnh và iframe.
Đưa WebViewAssetLoader
vào tệp hoạt động chính của bạn. Sau đây là một
ví dụ về cách tải nội dung web đơn giản từ thư mục thành phần:
Kotlin
private class LocalContentWebViewClient(private val assetLoader: WebViewAssetLoader) : WebViewClientCompat() { @RequiresApi(21) override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest ): WebResourceResponse? { return assetLoader.shouldInterceptRequest(request.url) } // To support API < 21. override fun shouldInterceptRequest( view: WebView, url: String ): WebResourceResponse? { return assetLoader.shouldInterceptRequest(Uri.parse(url)) } }
Java
private static class LocalContentWebViewClient extends WebViewClientCompat { private final WebViewAssetLoader mAssetLoader; LocalContentWebViewClient(WebViewAssetLoader assetLoader) { mAssetLoader = assetLoader; } @Override @RequiresApi(21) public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { return mAssetLoader.shouldInterceptRequest(request.getUrl()); } @Override @SuppressWarnings("deprecation") // To support API < 21. public WebResourceResponse shouldInterceptRequest(WebView view, String url) { return mAssetLoader.shouldInterceptRequest(Uri.parse(url)); } }
Ứng dụng phải định cấu hình một thực thể WebViewAssetLoader
cho phù hợp với nhu cầu. Chiến lược phát hành đĩa đơn
phần tiếp theo có ví dụ.
Tạo thành phần và tài nguyên trong ứng dụng
WebViewAssetLoader
dựa vào
PathHandler
để tải tài nguyên tương ứng với một đường dẫn tài nguyên nhất định. Mặc dù bạn
có thể triển khai giao diện này để truy xuất tài nguyên theo yêu cầu của ứng dụng,
Gói thư viện Webkit
AssetsPathHandler
và
ResourcesPathHandler
để tải các thành phần và tài nguyên Android tương ứng.
Để bắt đầu, hãy tạo các thành phần và tài nguyên cho ứng dụng của bạn. Nhìn chung, những điều sau sẽ áp dụng:
- Các tệp văn bản như HTML, JavaScript và CSS đều thuộc về các thành phần.
- Hình ảnh và các tệp nhị phân khác thuộc tài nguyên.
Để thêm tệp web dạng văn bản vào một dự án, hãy làm như sau:
- Trong Android Studio, hãy nhấp chuột phải vào app > (ứng dụng) > src > thư mục main rồi chọn Mới > Thư mục.
- Đặt tên cho thư mục là "Asset" (tài sản).
- Nhấp chuột phải vào thư mục Asset rồi nhấp vào New > (Mới >) Tệp.
Nhập
index.html
rồi nhấn phím Return hoặc Phím Enter. - Lặp lại bước trước đó để tạo một tệp trống cho
stylesheet.css
. - Điền nội dung vào hai mã tiếp theo vào các tệp trống đã tạo mẫu.
```html
<!-- index.html content -->
<html>
<head>
<!-- Tip: Use relative URLs when referring to other in-app content to give
your app code the flexibility to change the scheme or domain as
necessary. -->
<link rel="stylesheet" href="/assets/stylesheet.css">
</head>
<body>
<p>This file is loaded from in-app content.</p>
<p><img src="/res/drawable/android_robot.png" alt="Android robot" width="100"></p>
</body>
</html>
```
```css
<!-- stylesheet.css content -->
body {
background-color: lightblue;
}
```
Để thêm tệp web dựa trên hình ảnh vào dự án, hãy làm như sau:
Tải xuống
Android_symbol_green_RGB.png
vào máy cục bộ của bạn.Đổi tên tệp thành
android_robot.png
.Di chuyển tệp vào thư mục
main/res/drawable
của dự án theo cách thủ công trên ổ đĩa cứng của bạn.
Hình 4 cho thấy hình ảnh bạn đã thêm và văn bản từ các mã mẫu trước đó hiển thị trong ứng dụng.
Để hoàn tất ứng dụng này, hãy làm như sau:
Đăng ký trình xử lý và định cấu hình
AssetLoader
bằng cách thêm phương thức sau đây vào phương thứconCreate()
:Kotlin
val assetLoader = WebViewAssetLoader.Builder() .addPathHandler("/assets/", AssetsPathHandler(this)) .addPathHandler("/res/", ResourcesPathHandler(this)) .build() webView.webViewClient = LocalContentWebViewClient(assetLoader)
Java
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder() .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this)) .addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this)) .build(); mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
Tải nội dung bằng cách thêm mã sau vào phương thức
onCreate()
:Kotlin
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Kết hợp nội dung trong ứng dụng với tài nguyên từ trang web của bạn
Ứng dụng của bạn có thể cần tải kết hợp cả nội dung trong ứng dụng và nội dung từ
Internet, chẳng hạn như trang HTML trong ứng dụng do CSS của trang web tạo kiểu.
WebViewAssetLoader
hỗ trợ trường hợp sử dụng này. Nếu không có
Các thực thể PathHandler
có thể tìm thấy tài nguyên cho đường dẫn đã cho, WebView
sẽ rơi
quay lại để tải nội dung từ Internet. Nếu bạn kết hợp nội dung trong ứng dụng với
tài nguyên từ trang web của bạn, đặt trước đường dẫn thư mục, chẳng hạn như /assets/
hoặc
/resources/
đối với tài nguyên trong ứng dụng. Tránh lưu trữ bất kỳ tài nguyên nào trong
ở các vị trí đó.
Kotlin
val assetLoader = WebViewAssetLoader.Builder() .setDomain("example.com") // Replace this with your website's domain. .addPathHandler("/assets/", AssetsPathHandler(this)) .build() webView.webViewClient = LocalContentWebViewClient(assetLoader) val inAppHtmlUrl = "https://example.com/assets/index.html" webView.loadUrl(inAppHtmlUrl) val websiteUrl = "https://example.com/website/data.json" // JavaScript code to fetch() content from the same origin. val jsCode = "fetch('$websiteUrl')" + ".then(resp => resp.json())" + ".then(data => console.log(data));" webView.evaluateJavascript(jsCode, null)
Java
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder() .setDomain("example.com") // Replace this with your website's domain. .addPathHandler("/assets/", new AssetsPathHandler(this)) .build(); mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader)); String inAppHtmlUrl = "https://example.com/assets/index.html"; mWebView.loadUrl(inAppHtmlUrl); String websiteUrl = "https://example.com/website/data.json"; // JavaScript code to fetch() content from the same origin. String jsCode = "fetch('" + websiteUrl + "')" + ".then(resp => resp.json())" + ".then(data => console.log(data));"; mWebView.evaluateJavascript(jsCode, null);
Xem bản minh hoạ WebView
trên
GitHub
ví dụ về trang HTML trong ứng dụng tìm nạp dữ liệu JSON được lưu trữ trên web.
loadDataWithBaseURL
Khi ứng dụng của bạn chỉ cần tải một trang HTML và không cần chặn
các nguồn phụ, hãy cân nhắc sử dụng
loadDataWithBaseURL()
!
mà không cần phải có thành phần ứng dụng. Bạn có thể sử dụng như trong đoạn mã sau
mẫu:
Kotlin
val html = "<html><body><p>Hello world</p></body></html>" val baseUrl = "https://example.com/" webView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl)
Java
String html = "<html><body><p>Hello world</p></body></html>"; String baseUrl = "https://example.com/"; mWebView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl);
Chọn các giá trị cho đối số một cách cẩn thận. Hãy cân nhắc thực hiện những bước sau:
baseUrl
: đây là URL dùng để tải nội dung HTML của bạn. Đây phải là URL HTTP(S).data
: đây là nội dung HTML mà bạn muốn hiển thị dưới dạng một chuỗi.mimeType
: giá trị này thường phải được đặt thànhtext/html
.encoding
: không được dùng khibaseUrl
là URL HTTP(S), vì vậy được đặt thànhnull
.historyUrl
: giá trị này được đặt thành cùng một giá trị vớibaseUrl
.
Bạn nên sử dụng URL HTTP(S) làm baseUrl
, vì điều này sẽ giúp ích
đảm bảo ứng dụng của bạn tuân thủ chính sách về cùng nguồn gốc.
Nếu bạn không tìm được baseUrl
phù hợp với nội dung của mình và muốn sử dụng
loadData()
,
bạn phải mã hoá nội dung bằng
mã hoá phần trăm
hoặc
Base64
mã hoá.
Bạn nên chọn phương thức mã hoá Base64 và sử dụng API Android để mã hoá
theo phương thức lập trình, như trong mã mẫu sau:
Kotlin
val encodedHtml: String = Base64.encodeToString(html.toByteArray(), Base64.NO_PADDING) webView.loadData(encodedHtml, mimeType, "base64")
Java
String encodedHtml = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING); mWebView.loadData(encodedHtml, mimeType, "base64");
Những điều nên tránh
Có một số cách khác để tải nội dung trong ứng dụng, nhưng chúng tôi khuyên bạn chống lại chúng:
- URL
file://
và URLdata:
được coi là nguồn gốc không rõ ràng, nghĩa là chúng không thể tận dụng các API web mạnh mẽ nhưfetch()
hoặcXMLHttpRequest
.loadData()
sử dụngdata:
URL trong nội bộ, vì vậy chúng tôi khuyến khích bạn sử dụng HãyWebViewAssetLoader
hoặcloadDataWithBaseURL()
. - Mặc dù
WebSettings.setAllowFileAccessFromFileURLs()
vàWebSettings.setAllowUniversalAccessFromFileURLs()
có thể giải quyết vấn đề vớifile://
URL, bạn không nên đặt các lệnh này vớitrue
, vì làm như vậy khiến ứng dụng của bạn dễ bị tấn công khai thác. Bạn nên đặt rõ ràng các chế độ cài đặt này thànhfalse
ở mọi cấp độ API để có mức bảo mật mạnh nhất. - Cũng vì lý do đó, bạn không nên dùng
file://android_assets/
vàfile://android_res/
URL.AssetsHandler
vàResourcesHandler
là các lớp thay thế bất kỳ. - Tránh sử dụng
MIXED_CONTENT_ALWAYS_ALLOW
. Chế độ cài đặt này thường không cần thiết và làm giảm khả năng bảo mật của ứng dụng. Bạn nên tải nội dung trong ứng dụng qua cùng một giao thức — HTTP hoặc HTTPS—là tài nguyên của trang web của bạn và việc sử dụngMIXED_CONTENT_COMPATIBILITY_MODE
hoặcMIXED_CONTENT_NEVER_ALLOW
, khi phù hợp.