Tôi đã thảo luận trên CodeSpeedy về cách tạo ứng dụng Android tải trang web hoặc trang web trong ứng dụng Android bằng cách sử dụng lớp WebView dành cho Android có sẵn. Có thể bạn đã biết rằng bạn chỉ cần đặt URL bên trong loadUrl[] và bạn sẽ có thể tải trang web đó từ ứng dụng Android của mình
Bây giờ, giả sử bạn cần tải trang HTML cục bộ hoặc tệp HTML ngoại tuyến trong WebView. Vậy bạn phải làm gì? . Nó thực sự sẽ rất dễ dàng. Hãy đi về phía trước
Sử dụng lớp WebView của Android để tải tệp HTML cục bộ hoặc trang HTML ngoại tuyến
chúng ta đi đây. Chỉ cần nhớ loadUrl[] nơi tôi chỉ cho bạn cách tải trang web này
mWebView.loadUrl["//170.187.134.184"];
Nó sẽ tải trang web của chúng tôi trong ứng dụng Android. Bây giờ phải làm gì đối với tệp HTML ngoại tuyến hoặc cục bộ để nó cũng sẽ tải bên trong ứng dụng Android. Chà, để làm điều đó trước tiên, bạn cần tạo một thư mục tài nguyên Android mới và đặt tên cho nó là nội dung bên trong thư mục ứng dụng giống như hình bên dưới
Chà, bạn có thể đính kèm CSS, JavaScript và tất cả những gì bạn cần cho một mẫu HTML. Điều đó có nghĩa là bạn có thể đặt mẫu HTML hoàn chỉnh bên trong thư mục này. Bây giờ để tải nó trong WebView, bạn cần sử dụng mã được cung cấp bên dưới
myWebView.loadUrl["file:///android_asset/sample.html"];
Tất cả các mã khác sẽ được giữ nguyên. Để xem mã đầy đủ của tệp bố cục và Java chính, tôi giới thiệu bạn đến bài đăng này – Chuyển đổi mẫu HTML thành ứng dụng Android – Android Studio
Trong bản dựng AppStudio mới nhất của chúng tôi dành cho Android [được xây dựng qua Appstudio v. 5. 4. 142], khi chúng tôi cố gắng mở một địa phương. Tệp HTML trong WebView, ứng dụng hiển thị cho chúng tôi lỗi ERR_ACCESS_DENIED mà tôi cho rằng có liên quan đến sự cố Qt bên dưới. Chức năng này hoạt động trơn tru trong các bản phát hành trước [Mặc dù tôi nghĩ rằng bản dựng thành công cuối cùng là thông qua phiên bản 4. x. phát hành AppStudio]
Tôi tò mò liệu vấn đề này có nằm trong tầm ngắm của nhóm AppStudio cho bản phát hành sắp tới hay không, xin cảm ơn rất nhiều,
Bạn có thể cung cấp nội dung dựa trên web—chẳng hạn như HTML, JavaScript và CSS—để ứng dụng của bạn sử dụng mà bạn biên dịch tĩnh vào ứng dụng thay vì tìm nạp qua internet
Nội dung trong ứng dụng không yêu cầu truy cập internet hoặc tiêu tốn băng thông của người dùng và nếu nội dung được thiết kế dành riêng cho chỉ dành cho WebView—nghĩa là nội dung đó phụ thuộc vào việc giao tiếp với ứng dụng gốc—thì người dùng không thể vô tình tải nội dung đó vào một
Tuy nhiên, có một số nhược điểm đối với nội dung trong ứng dụng. Cập nhật nội dung dựa trên web yêu cầu gửi bản cập nhật ứng dụng mới và có khả năng nội dung 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ị của bạn nếu người dùng có phiên bản ứng dụng lỗi thời
WebViewAssetLoader
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]]; } }4 là một cách linh hoạt và hiệu quả để tải nội dung trong ứng dụng trong một đối tượng
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]]; } }5. Lớp này hỗ trợ
- Đang tải nội dung bằng URL HTTP[S] để tương thích với chính sách cùng nguồn gốc
- Đang tải các nguồn phụ như JavaScript, CSS, hình ảnh và iframe
Bao gồm
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]]; } }4 trong hồ sơ hoạt động chính của bạn. Sau đây là một ví dụ về tải nội dung web đơn giản từ thư mục nội dung
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 của bạn nên định cấu hình phiên bản
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]]; } }4 để phù hợp với nhu cầu của ứng dụng. Phần tiếp theo có một ví dụ
Tạo nội dung và tài nguyên trong ứng dụng
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]]; } }4 dựa vào phiên bản
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]]; } }9 để tải tài nguyên tương ứng với đườ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 khi ứng dụng của mình cần, nhưng thư viện Webkit sẽ gói
This file was loaded from in-app content
0 và
This file was loaded from in-app content
1 để tải nội dung và tài nguyên Android tương ứngĐể bắt đầu, hãy tạo một số nội dung và tài nguyên cho ứng dụng của bạn. Nói chung
- Các tệp văn bản như HTML, JavaScript và CSS thuộc về nội dung
- Hình ảnh và các tệp nhị phân khác thuộc về tài nguyên
Để thêm các tệp web dựa trên văn bản vào một dự án, hãy làm như sau
Trong Android Studio, nhấp chuột phải vào ứng dụng > src > thư mục chính rồi chọn Mới > Thư mục
Hình 1. Tạo một thư mục nội dung cho dự án của bạnĐặt tên cho thư mục "tài sản. "
Hình 2. Đặt tên cho thư mục tài sảnBấm chuột phải vào thư mục nội dung rồi bấm Mới > Tệp. Nhập
2 và nhấn Return hoặc EnterThis file was loaded from in-app content
Hình 3. Tạo các tệp có tên của các mẫu mã sauLặp lại bước trước đó để tạo một tệp trống cho
3This file was loaded from in-app content
Điền vào các tệp trống bạn đã tạo với nội dung trong hai mẫu mã tiếp theo
mục lục. html
This file was loaded from in-app content
biểu định kiểu. css
body {
background-color: lightblue;
}
Để thêm tệp web dựa trên hình ảnh vào dự án của bạn, hãy làm như sau
Tải xuống tệp
4 về máy cục bộ của bạnThis file was loaded from in-app content
Đổi tên tệp thành
5This file was loaded from in-app content
Di chuyển tệp theo cách thủ công vào thư mục
6 của dự án trên ổ cứng của bạnThis file was loaded from in-app content
Hình 4 hiển thị hình ảnh bạn đã thêm và văn bản từ các mẫu mã trước đó được hiển thị trong một ứng dụng
hinh 4. Tệp HTML trong ứng dụng và tệp hình ảnh được hiển thị trong ứng dụng
Để hoàn thành ứng dụng, hãy làm như sau
Đăng ký trình xử lý và định cấu hình
7 bằng cách thêm đoạn mã sau vào phương thứcThis file was loaded from in-app content
8This file was loaded from in-app content
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 đoạn mã sau vào phương thức
8This file was loaded from in-app content
Kotlin
webView.loadUrl["//appassets.androidplatform.net/assets/index.html"]
Java
mWebView.loadUrl["//appassets.androidplatform.net/assets/index.html"];
Kết hợp nội dung trong ứng dụng với các tài nguyên từ trang web của bạn
Ứng dụng của bạn có thể cần tải hỗn hợp nội dung trong ứng dụng và nội dung từ internet, chẳng hạn như trang HTML trong ứng dụng được tạo kiểu bởi CSS của trang web của bạn.
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]]; } }4 hỗ trợ trường hợp sử dụng này. Nếu không ai trong số
body {
background-color: lightblue;
}
1 đã đăng ký có thể tìm thấy tài nguyên cho đường dẫn nhất định, thì WebView sẽ quay lại tải nội dung từ internet. Nếu bạn đang trộn nội dung trong ứng dụng với các tài nguyên từ trang web của mình, hãy đảm bảo dành riêng các đường dẫn thư mục, chẳng hạn như body {
background-color: lightblue;
}
2 hoặc body {
background-color: lightblue;
}
3, cho các tài nguyên trong ứng dụng. Tránh lưu trữ bất kỳ tài nguyên nào từ trang web của bạn ở những 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 = "//example.com/assets/index.html"
webView.loadUrl[inAppHtmlUrl]
val websiteUrl = "//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 = "//example.com/assets/index.html";
mWebView.loadUrl[inAppHtmlUrl];
String websiteUrl = "//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 trình diễn WebView trên GitHub để biết ví dụ về trang HTML trong ứng dụng đang tìm nạp dữ liệu JSON được lưu trữ trên web
tảiDataWithBaseURL
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 , không yêu cầu nội dung ứng dụng. Bạn có thể sử dụng nó như trong mẫu mã sau
Kotlin
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]];
}
}
0Java
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]];
}
}
1
Chọn giá trị đối số một cách cẩn thận
5. Đây là URL mà nội dung HTML của bạn sẽ được tải dưới dạng. Đây phải là một URL HTTP[S]body { background-color: lightblue; }
6. Đây là nội dung HTML bạn muốn hiển thị, dưới dạng chuỗibody { background-color: lightblue; }
7. Điều này thường nên được đặt thànhbody { background-color: lightblue; }
8body { background-color: lightblue; }
9. Điều này không được sử dụng khibody { background-color: lightblue; }
5 là URL HTTP[S], vì vậy có thể được đặt thànhbody { background-color: lightblue; }
val assetLoader = WebViewAssetLoader.Builder[] .addPathHandler["/assets/", AssetsPathHandler[this]] .addPathHandler["/res/", ResourcesPathHandler[this]] .build[] webView.webViewClient = LocalContentWebViewClient[assetLoader]
1val assetLoader = WebViewAssetLoader.Builder[] .addPathHandler["/assets/", AssetsPathHandler[this]] .addPathHandler["/res/", ResourcesPathHandler[this]] .build[] webView.webViewClient = LocalContentWebViewClient[assetLoader]
2. Giá trị này được đặt thành cùng giá trị với
5body { background-color: lightblue; }
Chúng tôi thực sự khuyên bạn nên sử dụng URL HTTP[S] làm
body {
background-color: lightblue;
}
5, vì điều này đảm bảo ứng dụng của bạn tuân thủ chính sách cùng nguồn gốcNếu bạn không thể tìm thấy
body {
background-color: lightblue;
}
5 phù hợp cho nội dung của mình và muốn sử dụng , thì bạn phải mã hóa nội dung bằng mã hóa phần trăm hoặc. Chúng tôi thực sự khuyên bạn nên chọn mã hóa Base64 và sử dụng API Android để mã hóa mã này theo chương trình, như được hiển thị trong mẫu mã sauKotlin
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]];
}
}
2Java
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]];
}
}
3
val assetLoader = WebViewAssetLoader.Builder[] .addPathHandler["/assets/", AssetsPathHandler[this]] .addPathHandler["/res/", ResourcesPathHandler[this]] .build[] webView.webViewClient = LocalContentWebViewClient[assetLoader]6 yêu cầu dữ liệu HTML được mã hóa theo phần trăm. Mã hóa phần trăm bằng tay dễ bị lỗi và không có API Android nào để thực hiện việc này theo chương trình. Chúng tôi thực sự khuyên bạn nên chuyển sang
body {
background-color: lightblue;
}
4 để tránh yêu cầu này hoặc sử dụng API Base64 để mã hóa nội dung, như được hiển thị trong mẫu mã trước đó.