محتوای درون برنامه را بارگیری کنید

می‌توانید محتوای مبتنی بر وب مانند HTML، جاوا اسکریپت و CSS را برای برنامه‌تان فراهم کنید تا به‌جای واکشی از طریق اینترنت، به‌صورت ایستا در برنامه کامپایل کنید.

محتوای درون برنامه ای نیازی به دسترسی به اینترنت یا مصرف پهنای باند کاربر ندارد. اگر محتوا به طور خاص فقط برای WebView طراحی شده باشد - یعنی به برقراری ارتباط با یک برنامه بومی بستگی دارد - کاربران نمی توانند به طور تصادفی آن را در یک مرورگر وب بارگذاری کنند.

با این حال، برخی از اشکالات در محتوای درون برنامه وجود دارد. به‌روزرسانی محتوای مبتنی بر وب نیاز به ارسال به‌روزرسانی جدید برنامه دارد و اگر کاربران نسخه‌های قدیمی برنامه را داشته باشند، احتمال عدم تطابق محتوای بین آنچه در وب‌سایت و آنچه در برنامه موجود است در دستگاه شما وجود دارد.

WebViewAssetLoader

WebViewAssetLoader یک روش منعطف و کارآمد برای بارگیری محتوای درون برنامه در یک شی WebView است. این کلاس موارد زیر را پشتیبانی می کند:

  • در حال بارگیری محتوا با یک URL HTTP(S) برای سازگاری با خط مشی مبدا یکسان .
  • بارگیری منابع فرعی مانند جاوا اسکریپت، CSS، تصاویر و iframes.

WebViewAssetLoader در فایل فعالیت اصلی خود قرار دهید. در زیر نمونه ای از بارگیری محتوای وب ساده از پوشه assets آورده شده است:

کاتلین

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، جاوا اسکریپت و CSS به دارایی ها تعلق دارند.
  • تصاویر و سایر فایل های باینری متعلق به منابع هستند.

برای افزودن فایل های وب مبتنی بر متن به پروژه، موارد زیر را انجام دهید:

  1. در Android Studio، روی برنامه > src > پوشه اصلی کلیک راست کرده و سپس New > Directory را انتخاب کنید.
    تصویری که منوهای ایجاد فهرست راهنمای اندروید استودیو را نشان می‌دهد
    شکل 1. یک پوشه دارایی برای پروژه خود ایجاد کنید.
  2. نام پوشه را "assets" بگذارید.
    تصویری که پوشه دارایی را نشان می دهد
    شکل 2. پوشه assets را نام ببرید.
  3. روی پوشه assets کلیک راست کرده و سپس New > File را کلیک کنید. 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);

برای نمونه‌ای از صفحه HTML درون‌برنامه‌ای که داده‌های JSON میزبان وب را واکشی می‌کند ، نسخه نمایشی WebView را در GitHub ببینید.

loadDataWithBaseURL

وقتی برنامه شما فقط نیاز به بارگیری یک صفحه 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 : این نشانی اینترنتی است که محتوای 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:// آدرس‌ها و data: نشانی‌های اینترنتی منشأ غیرشفاف در نظر گرفته می‌شوند، به این معنی که نمی‌توانند از 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 استفاده کنید.