Загрузка контента в приложении

Вы можете предоставить веб-контент, такой как HTML, JavaScript и CSS, для использования в вашем приложении, который вы статически компилируете в приложение, а не загружаете через Интернет.

Контент в приложении не требует доступа в Интернет и не потребляет пропускную способность пользователя. Если контент разработан специально только для WebView , то есть зависит от взаимодействия с собственным приложением, пользователи не смогут случайно загрузить его в веб-браузер.

Однако у контента внутри приложения есть некоторые недостатки. Обновление веб-контента требует отправки нового обновления приложения, и существует вероятность несоответствия содержимого между тем, что находится на веб-сайте, и тем, что находится в приложении на вашем устройстве, если у пользователей устаревшие версии приложения.

Вебвиевассетлоадер

WebViewAssetLoader — это гибкий и эффективный способ загрузки содержимого приложения в объект WebView . Этот класс поддерживает следующее:

Включите WebViewAssetLoader в свой основной файл активности. Ниже приведен пример загрузки простого веб-содержимого из папки ресурсов:

Котлин

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

Ява

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 объединяет AssetsPathHandler и ResourcesPathHandler для загрузки ресурсов и ресурсов Android соответственно.

Для начала создайте активы и ресурсы для своего приложения. Обычно применяется следующее:

  • Текстовые файлы, такие как HTML, JavaScript и CSS, относятся к ресурсам.
  • Изображения и другие двоичные файлы относятся к ресурсам.

Чтобы добавить в проект текстовые веб-файлы, выполните следующие действия:

  1. В Android Studio щелкните правой кнопкой мыши приложение > src > основная папка и выберите «Создать» > «Каталог» .
    Изображение, показывающее меню создания каталога Android Studio.
    Рисунок 1. Создайте папку ресурсов для вашего проекта.
  2. Назовите папку «активы».
    Изображение, показывающее папку с ресурсами
    Рисунок 2. Назовите папку ресурсов.
  3. Щелкните правой кнопкой мыши папку ресурсов и выберите «Создать» > «Файл» . Введите index.html и нажмите клавишу Return или Enter .
  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;
}
```

Чтобы добавить в проект веб-файл на основе изображения, выполните следующие действия:

  1. Загрузите файл Android_symbol_green_RGB.png на свой локальный компьютер.

  2. Переименуйте файл в android_robot.png .

  3. Вручную переместите файл в каталог main/res/drawable вашего проекта на жестком диске.

На рис. 4 показано добавленное вами изображение и текст из предыдущих примеров кода, отображаемый в приложении.

Изображение, демонстрирующее результаты обработки приложения.
Рисунок 4. HTML-файл внутри приложения и файл изображения, отображаемые в приложении.

Чтобы завершить работу приложения, выполните следующие действия:

  1. Зарегистрируйте обработчики и настройте AssetLoader , добавив следующий код в метод onCreate() :

    Котлин

    val assetLoader = WebViewAssetLoader.Builder()
                           .addPathHandler("/assets/", AssetsPathHandler(this))
                           .addPathHandler("/res/", ResourcesPathHandler(this))
                           .build()
    webView.webViewClient = LocalContentWebViewClient(assetLoader)

    Ява

    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() :

    Котлин

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

    Ява

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

Смешайте контент внутри приложения с ресурсами вашего сайта.

Вашему приложению может потребоваться загрузить как контент из приложения, так и контент из Интернета, например HTML-страницу внутри приложения, оформленную с помощью CSS вашего веб-сайта. WebViewAssetLoader поддерживает этот вариант использования. Если ни один из зарегистрированных экземпляров PathHandler не может найти ресурс по данному пути, WebView возвращается к загрузке контента из Интернета. Если вы смешиваете контент приложения с ресурсами своего веб-сайта, зарезервируйте пути к каталогам, например /assets/ или /resources/ , для ресурсов приложения. Избегайте хранения каких-либо ресурсов вашего веб-сайта в этих местах.

Котлин

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)

Ява

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, где приведен пример HTML-страницы в приложении, извлекающей данные JSON, размещенные в Интернете.

ЗагрузитьДанныеВиБасеURL

Если вашему приложению нужно только загрузить HTML-страницу и не нужно перехватывать подресурсы, рассмотрите возможность использования loadDataWithBaseURL() , для которого не требуются ресурсы приложения. Вы можете использовать его, как показано в следующем примере кода:

Котлин

val html = "<html><body><p>Hello world</p></body></html>"
val baseUrl = "https://example.com/"

webView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl)

Ява

String html = "<html><body><p>Hello world</p></body></html>";
String baseUrl = "https://example.com/";

mWebView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl);

Тщательно выбирайте значения аргументов. Учтите следующее:

  • baseUrl : это URL-адрес, по которому загружается ваш HTML-контент. Это должен быть URL-адрес HTTP(S).
  • data : это HTML-содержимое, которое вы хотите отобразить в виде строки.
  • mimeType : обычно должно быть установлено значение text/html .
  • encoding : не используется, если baseUrl является URL-адресом HTTP(S), поэтому для него можно установить значение null .
  • historyUrl : для него установлено то же значение, что и baseUrl .

Мы настоятельно рекомендуем использовать URL-адрес HTTP(S) в качестве baseUrl , поскольку это помогает гарантировать, что ваше приложение соответствует политике одного и того же источника.

Если вы не можете найти подходящий baseUrl для своего контента и предпочитаете использовать loadData() , вам необходимо закодировать контент с помощью процентной кодировки или кодировки Base64 . Мы настоятельно рекомендуем выбрать кодировку Base64 и использовать API-интерфейсы Android для программного кодирования, как показано в следующем примере кода:

Котлин

val encodedHtml: String = Base64.encodeToString(html.toByteArray(), Base64.NO_PADDING)

webView.loadData(encodedHtml, mimeType, "base64")

Ява

String encodedHtml = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING);

mWebView.loadData(encodedHtml, mimeType, "base64");

Чего следует избегать

Есть несколько других способов загрузки контента в приложении, но мы настоятельно не рекомендуем их использовать:

  • file:// URL-адреса и data: URL-адреса считаются непрозрачными источниками , то есть они не могут использовать преимущества мощных веб-API, таких как fetch() или XMLHttpRequest . loadData() внутренне использует data: URL-адреса, поэтому мы рекомендуем вместо этого использовать WebViewAssetLoader или loadDataWithBaseURL() .
  • Хотя WebSettings.setAllowFileAccessFromFileURLs() и WebSettings.setAllowUniversalAccessFromFileURLs() могут обойти проблемы с URL-адресами file:// , мы не рекомендуем устанавливать для них значение true , поскольку это делает ваше приложение уязвимым для файловых эксплойтов. Мы рекомендуем явно установить для них значение false на всех уровнях API для обеспечения максимальной безопасности.
  • По тем же причинам мы не рекомендуем использовать URL-адреса file://android_assets/ и file://android_res/ . Классы AssetsHandler и ResourcesHandler предназначены для замены.
  • Избегайте использования MIXED_CONTENT_ALWAYS_ALLOW . Этот параметр обычно не нужен и ослабляет безопасность вашего приложения. Мы рекомендуем загружать содержимое приложения по той же схеме (HTTP или HTTPS), что и ресурсы вашего веб-сайта, и использовать MIXED_CONTENT_COMPATIBILITY_MODE или MIXED_CONTENT_NEVER_ALLOW в зависимости от ситуации.