تحميل محتوى داخل التطبيق

يمكنك تقديم محتوى مستند إلى الويب — مثل HTML وJavaScript CSS: ليتمكّن التطبيق من استخدامها من خلال تجميعها بشكل ثابت في التطبيق بدلاً من من الجلب عبر الإنترنت.

لا يتطلب المحتوى داخل التطبيق الوصول إلى الإنترنت أو استهلاك معدّل نقل البيانات للمستخدم. في حال حذف تمّ تصميم المحتوى خصيصًا لـ WebView فقط، أي على الاتصال بتطبيق محلي، فلن يتمكن المستخدمون من تحميله في متصفح الويب.

ومع ذلك، هناك بعض السلبيات للمحتوى داخل التطبيق. تعديل المحتوى المستند إلى الويب شحن تحديث جديد للتطبيق، وثمة احتمال عدم تطابق بين المحتوى المعروض على الموقع الإلكتروني والمحتوى المتوفّر في التطبيق على جهازك لدى المستخدمين إصدارات قديمة من التطبيق.

أداة WebViewAssetLoader

WebViewAssetLoader هو طريقة مرنة وفعّالة لتحميل المحتوى داخل التطبيق الكائن WebView. تدعم هذه الفئة التالي:

  • تحميل محتوى باستخدام عنوان URL يستخدم بروتوكول HTTP(S) للتوافق مع المصدر نفسه .
  • تحميل موارد فرعية، مثل JavaScript وCSS والصور وإطارات iframe

أدرِج "WebViewAssetLoader" في ملف النشاط الرئيسي. فيما يلي مثال لتحميل محتوى ويب بسيط من مجلد "Assets" (الأصول):

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 AssetsPathHandler أو ResourcesPathHandler لتحميل أصول وموارد Android على التوالي.

للبدء، أنشئ مواد عرض وموارد لتطبيقك. بشكل عام، تنطبق المعلومات التالية:

  • تنتمي الملفات النصية، مثل HTML وJavaScript وCSS، إلى مواد العرض.
  • تنتمي الصور والملفات الثنائية الأخرى إلى الموارد.

لإضافة ملفات ويب نصية إلى مشروع، قم بما يلي:

  1. في "استوديو Android"، انقر بزر الماوس الأيمن على التطبيق > src > المجلد الرئيسي ثم اختر جديد > الدليل.
    صورة تعرض قوائم إنشاء دليل على &quot;استوديو Android&quot;
    الشكل 1. إنشاء مجلد مواد عرض مشروعك.
  2. أدخِل اسمًا للمجلد "مواد العرض".
    صورة تعرض مجلد مواد العرض
    الشكل 2. أدخِل اسمًا لمجلد مواد العرض.
  3. انقر بزر الماوس الأيمن على المجلد assets، ثم انقر على جديد >. ملف. أدخِل 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():

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

المزج بين المحتوى داخل التطبيق والموارد من موقعك الإلكتروني

قد يحتاج تطبيقك إلى تحميل مزيج من المحتوى داخل التطبيق والمحتوى من الإنترنت، مثل صفحة HTML داخل التطبيق بنمط من خلال خدمة مقارنة الأسعار (CSS) الخاصة بموقعك الإلكتروني. تتوافق السمة 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 لعرض مثال لصفحة HTML داخل التطبيق تجلب بيانات JSON المستضافة على الويب.

loadDataWithBaseURL

عندما يحتاج تطبيقك إلى تحميل صفحة 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: هذا هو عنوان 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 واستخدام واجهات برمجة تطبيقات Android لترميز البيانات. ذلك آليًا، كما هو موضّح في نموذج الرمز البرمجي التالي:

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:// عنوان URL وdata: عنوان URL مصادر غير واضحة. مما يعني أنه لا يمكنهم الاستفادة من واجهات برمجة تطبيقات الويب القوية مثل fetch() أو XMLHttpRequest. يستخدم loadData() داخليًا عناوين URL data:، لذا ننصح باستخدام WebViewAssetLoader أو loadDataWithBaseURL() بدلاً من ذلك.
  • رغم WebSettings.setAllowFileAccessFromFileURLs() أو WebSettings.setAllowUniversalAccessFromFileURLs() يعمل على حل المشكلات المتعلقة بعناوين URL file://، فلا ننصح بإعداد هذه إلى true لأن ذلك يؤدي إلى جعل التطبيق عرضة للاختراق استنادًا إلى الملفات عمليات الاختراق. ننصح بضبط هذه الإعدادات صراحةً على false على جميع مستويات واجهة برمجة التطبيقات. لتعزيز الأمان
  • للأسباب نفسها، نقترح ضد file://android_assets/ و file://android_res/ عنوان URL. AssetsHandler وResourcesHandler الفئات أن تكون بدائل جاهزة.
  • تجنب استخدام MIXED_CONTENT_ALWAYS_ALLOW هذا الإعداد غير ضروري بوجه عام، وهو ما يُضعف أمان تطبيقك. نوصي بتحميل المحتوى داخل التطبيق باستخدام المخطط نفسه، سواء HTTP أو HTTPS - بمثابة موارد موقعك الإلكتروني واستخدام MIXED_CONTENT_COMPATIBILITY_MODE أو MIXED_CONTENT_NEVER_ALLOW, حسبما تقتضي الحاجة.