加载应用内的内容

您可以提供基于网络的内容,如 HTML、JavaScript 和 CSS - 供应用使用,而您将其静态编译到应用中 而不是通过互联网提取

应用内的内容不需要接入互联网,也不会占用用户的带宽。如果 该内容仅面向WebView而设计,也就是说, 取决于与本机应用的通信,因此用户不可能 将其加载到网络浏览器中。

不过,应用内的内容也有一些缺点。更新基于网络的内容 需要发布新的应用更新,并且有可能出现不一致的情况 网站上的内容与设备上应用中的内容之间 用户使用应用版本过旧。

WebViewAssetLoader

WebViewAssetLoader是 一种灵活、高效的方法 WebView 对象。此类支持 以下:

  • 使用 HTTP(S) 网址加载内容,以便与同源兼容 政策
  • 加载 JavaScript、CSS、图片和 iframe 等子资源。

WebViewAssetLoader 添加到主 activity 文件中。以下是 从资源文件夹加载简单网页内容的示例:

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));
    }
}

您的应用必须配置 WebViewAssetLoader 实例以满足其需求。通过 有一个示例。

创建应用内素材资源和资源

WebViewAssetLoader依赖于 PathHandler 实例加载与给定资源路径对应的资源。虽然您 可以实现此接口以根据应用、 Webkit 库软件包 AssetsPathHandlerResourcesPathHandler 分别用于加载 Android 资源和资源。

首先,请为您的应用创建资源和资源。通常, 以下规则:

  • HTML、JavaScript 和 CSS 等文本文件都属于 assets。
  • 映像和其他二进制文件属于资源。

如需向项目添加基于文本的 Web 文件,请执行以下操作:

  1. 在 Android Studio 中,右键点击 app >src >main 文件夹 然后选择新建 >目录。 <ph type="x-smartling-placeholder">
    </ph> 显示 Android Studio create-directory 菜单的图片 <ph type="x-smartling-placeholder">
    </ph> 图 1.为您的文件创建资源文件夹 项目。
  2. 将该文件夹命名为“assets”。
    显示素材资源文件夹的图片
    图 2. 为素材资源文件夹命名。
  3. 右键点击 assets 文件夹,然后点击新建 >文件。 输入 index.html,然后按回车键Enter 键。 <ph type="x-smartling-placeholder">
  4. 重复执行上一步,为 stylesheet.css
  5. 使用下面两个代码中的内容填充您创建的空文件 示例。
```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;
}
```

如需向项目中添加基于图片的 Web 文件,请执行以下操作:

  1. 下载 Android_symbol_green_RGB.png 复制到您的本地机器

  2. 将文件重命名为 android_robot.png

  3. 手动将文件移入项目的 main/res/drawable 目录中 您的硬盘。

图 4 显示了您添加的图片以及上述代码示例中的文本 在应用中呈现

显示应用呈现输出的图片
图 4. 应用内 HTML 文件和图片文件 在应用中呈现

如需完成该应用,请执行以下操作:

  1. 注册处理程序并配置 AssetLoader,方法是添加 将以下代码添加到 onCreate() 方法中:

    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));
    
  2. 将以下代码添加到 onCreate() 方法即可加载内容:

    Kotlin

    webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
    

    Java

    mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
    

将应用内内容与来自您网站的资源混合使用

您的应用可能需要同时加载应用内内容和 例如,由网站的 CSS 设定样式的应用内 HTML 页面。 WebViewAssetLoader 支持此用例。如果没有任何一个已注册的 PathHandler 个实例可以找到给定路径的资源,WebView 个实例落入 从互联网加载内容的过程。如果您将应用内内容 网站中的资源,预留目录路径,例如 /assets//resources/,适用于应用内资源。避免存储来自您的 位于这些地理位置的网站。

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);

观看 WebView 演示 GitHub 获取提取网站托管的 JSON 数据的应用内 HTML 页面示例。

使用基准网址加载数据

当您的应用只需要加载 HTML 页面,不需要拦截页面时, 子资源,请考虑使用 loadDataWithBaseURL()、 不需要应用素材资源您可以使用它,如以下代码所示 示例:

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);

请谨慎选择参数值。注意事项:

  • baseUrl:这是 HTML 内容的加载网址。该参数必须是 HTTP(S) 网址。
  • data:这是您要以字符串形式显示的 HTML 内容。
  • mimeType:通常必须设置为 text/html
  • encoding:当 baseUrl 是 HTTP(S) 网址时,不使用此属性,因此可以 已设置为 null
  • historyUrl:设置为与 baseUrl 相同的值。

我们强烈建议使用 HTTP(S) 网址作为 baseUrl,因为这有助于 确保您的应用符合同源政策。

如果您找不到适合您的内容的baseUrl,而是想使用 loadData(), 你必须使用 百分比编码Base64 编码。 我们强烈建议选择 Base64 编码并使用 Android API 进行编码 以编程方式执行此操作,如以下代码示例所示:

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");

需要避免的事项

还有其他几种方法可以加载应用内内容,不过我们强烈建议您 反对它们:

  • file:// 个网址和 data: 个网址被视为不透明来源, 这意味着它们无法利用强大的 Web API, fetch()XMLHttpRequestloadData() 在内部使用 data: 网址,因此我们建议您使用 WebViewAssetLoaderloadDataWithBaseURL()
  • 虽然 WebSettings.setAllowFileAccessFromFileURLs()WebSettings.setAllowUniversalAccessFromFileURLs() 可以解决file://网址的问题,我们建议不要将 以便将其告知 true,因为这样做会导致您的应用容易受到文件级攻击 漏洞。我们建议在所有 API 级别上将这些级别明确设置为 false ,从而获得最强大的安全机制。
  • 出于同样的原因,我们建议不要使用 file://android_assets/file://android_res/ 个网址。AssetsHandlerResourcesHandler 而是直接替换。
  • 避免使用 MIXED_CONTENT_ALWAYS_ALLOW。 此设置通常不是必需的,而且会降低应用的安全性。 我们建议您通过相同的协议(HTTP 或 HTTPS - 作为您网站的资源,并使用 MIXED_CONTENT_COMPATIBILITY_MODEMIXED_CONTENT_NEVER_ALLOW, 视情况而定。