يمكنك تقديم محتوى مستند إلى الويب — مثل 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، إلى مواد العرض.
- تنتمي الصور والملفات الثنائية الأخرى إلى الموارد.
لإضافة ملفات ويب نصية إلى مشروع، قم بما يلي:
- في "استوديو Android"، انقر بزر الماوس الأيمن على التطبيق > src > المجلد الرئيسي ثم اختر جديد > الدليل.
- أدخِل اسمًا للمجلد "مواد العرض".
- انقر بزر الماوس الأيمن على المجلد assets، ثم انقر على جديد >. ملف.
أدخِل
index.html
واضغط على الزر Return أو Enter. - كرر الخطوة السابقة لإنشاء ملف فارغ لـ
stylesheet.css
- املأ الملفات الفارغة التي أنشأتها بالمحتوى في الرمزَين التاليَين العينات.
```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;
}
```
لإضافة ملف ويب مستند إلى صورة إلى مشروعك، قم بما يلي:
تنزيل
Android_symbol_green_RGB.png
إلى جهازك المحلي.أعِد تسمية الملف إلى "
android_robot.png
".يمكنك نقل الملف يدويًا إلى دليل
main/res/drawable
الخاص بمشروعك على محرك الأقراص الثابتة.
يعرض الشكل 4 الصورة التي أضفتها والنص من عيّنات التعليمات البرمجية السابقة. المعروض في التطبيق.
لإكمال التطبيق، نفِّذ ما يلي:
سجِّل المعالِجات واضبط
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));
يمكنك تحميل المحتوى من خلال إضافة الرمز التالي إلى طريقة
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()
داخليًا عناوين URLdata:
، لذا ننصح باستخدامWebViewAssetLoader
أوloadDataWithBaseURL()
بدلاً من ذلك. - رغم
WebSettings.setAllowFileAccessFromFileURLs()
أوWebSettings.setAllowUniversalAccessFromFileURLs()
يعمل على حل المشكلات المتعلقة بعناوين URLfile://
، فلا ننصح بإعداد هذه إلى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
, حسبما تقتضي الحاجة.