وقت استجابة التنقّل هو مقياس مهم لتجربة المستخدم. لمساعدة المطوّرين في تقليل وقت الاستجابة هذا، توفّر WebView واجهات برمجة تطبيقات للتحميل المبني على توقّع، ما يتيح لتطبيقك جلب المحتوى أو عرضه قبل أن ينتقل إليه المستخدم بشكل صريح.
يتيح WebView ثلاثة أنواع أساسية من التحميل التخميني: Preconnect وPrefetch وPrerender.
من خلال تنفيذ استراتيجية التحميل المبني على توقُّع، يمكنك تحقيق ما يلي:
- تقليل كبير في وقت استجابة تحميل محتوى الويب: يمكنك نقل وقت بدء الشبكة إلى وقت أبكر في دورة حياة التطبيق.
- معدّلات نجاح أعلى في التنقّل: من خلال التسخين المُسبَق للشبكة وذاكرة التخزين المؤقت، يصبح من غير المرجّح أن يتعذّر التنقّل بسبب مشاكل عابرة في الشبكة.
- تحسين سرعة الاستجابة الظاهرية: تتيح عملية العرض المسبق، على وجه الخصوص، عمليات انتقال فورية تجعل التطبيق يبدو أسرع بكثير.
اختيار استراتيجية التحميل المبني على توقّع
يتمثّل الفرق الأساسي بين هاتين الاستراتيجيتين في نطاقهما: تعتمد واجهة برمجة التطبيقات Preconnect على المصدر، ما يعني أنّها تتطلّب النطاق المستهدف فقط. تستند واجهات برمجة التطبيقات الخاصة بجلب البيانات مسبقًا وعرضها مسبقًا إلى عناوين URL، ما يعني أنّها تتطلّب مسار صفحة الويب المحدّد.
بما أنّ Preconnect تعمل على مستوى المصدر، يمكن بدءها في وقت مبكر جدًا من دورة حياة التطبيق، حتى قبل معرفة المحتوى أو الصفحة المحدّدة التي سينتقل إليها المستخدم.
يقارن الجدول التالي بين هذه الاستراتيجيات الثلاث لمساعدتك في اختيار الاستراتيجية المناسبة لحالة الاستخدام:
| الميزة | الاتصال المُسبَق | الجلب المُسبَق | Prerender |
|---|---|---|---|
| الهدف الأساسي | توطيد العلاقة | تخزين ملفات HTML مؤقتًا فقط (بدون JavaScript أو CSS) | العرض المسبق للصفحة بأكملها |
| النطاق | مستوى الملف الشخصي (يتم مشاركته في جميع عروض الويب) | مستوى الملف الشخصي (يتم مشاركته في جميع عروض الويب) | مستوى WebView (مرتبط بمكوّن WebView معيّن) |
| Jetpack WebKit API | androidx.webkit.Profile |
androidx.webkit.Profile |
androidx.webkit.WebViewCompat |
| طُرق واجهة برمجة التطبيقات الأساسية | preconnect(...) |
prefetchUrlAsync(...) |
prerenderUrlAsync(...) |
| الإعداد | لا ينطبق | PrefetchCache.setMaxPrefetches()PrefetchCache.setPrefetchTtlSeconds() |
setMaxPrerenders() |
| استخدام الموارد | منخفضة (الشبكة) | متوسط (الشبكة، الذاكرة) | مرتفع (وحدة المعالجة المركزية والذاكرة والشبكة) |
| حالات الاستخدام | عندما يكون المصدر المستهدف معروفًا، ولكن لم يتم تحديد عنوان URL معيّن بعد. | عندما يكون عنوان URL الدقيق معروفًا ومن المحتمل أن يتم الانتقال إليه، مع مشاركة التخزين المؤقت بين WebViews | عندما يكون عنوان URL الدقيق معروفًا ويكون التنقّل مؤكّدًا إلى حد كبير ضمن WebView معيّن |
| المزايا | إعداد اتصال أسرع لأي عنوان URL على المصدر | تحميل أسرع للشبكة لعناوين URL المطابِقة | التنقّل الفوري عند التفعيل |
الاتصال المُسبَق بالمصادر
تؤدي عملية الاتصال المسبق إلى تسريع عمليات التحميل المستقبلية من خلال إجراء عمليات بحث نظام أسماء النطاقات (DNS) وتأكيد اتصال بروتوكول التحكم في الإرسال (TCP) وبروتوكول طبقة المقابس الآمنة (SSL) بشكل استباقي لمصدر محدّد.
على عكس الجلب المُسبَق والعرض المُسبَق اللذين يتطلّبان عنوان URL دقيقًا للوجهة، يعتمد الاتصال المُسبَق بشكل صارم على المصدر. يتيح لك ذلك إجراء طلب Preconnect قبل وقت طويل من طلبَي Prefetch وPrerender.
تؤدي هذه الاستراتيجية ذات الموارد المنخفضة على مستوى الملف الشخصي إلى تقليل وقت الاستجابة الأوّلي لأي مشاركة في WebView ضمن الملف الشخصي، شرط ألا يكون قد تم الانتقال إلى المصدر من قبل. يبقى الاتصال مفتوحًا لمدة 30 ثانية تقريبًا، ما يتيح الاستفادة من أي طلبات HTTP أو عمليات تنقّل أو موارد فرعية لاحقة من مصادر متعددة من خلال إلغاء عبء عملية المصافحة.
التنفيذ
لبدء عملية ربط مسبق، اتّصِل بـ preconnect(String url) على مثيل Profile. يجب طلب البيانات من واجهة برمجة التطبيقات هذه في سلسلة التعليمات الخاصة بواجهة المستخدم، ويجب أن تتوافق مع WebViewFeature.PRECONNECT.
تعمل واجهة برمجة التطبيقات على المصدر، ولكن لتسهيل الأمر، يمكن تقديم عنوان URL كامل (مثل https://www.example.com/index.html). ويتم تلقائيًا التعامل مع هذا العنوان على أنّه طلب إلى المصدر (على سبيل المثال، https://www.example.com). ويمكن ربط مصادر متعددة من خلال طلب البيانات من واجهة برمجة التطبيقات هذه عدة مرات.
Kotlin
// Must be called on the @UiThread
if (WebViewFeature.isFeatureSupported(WebViewFeature.PRECONNECT)) {
profile.preconnect("https://www.example.com/index.html")
// This initiates a connection to the origin https://www.example.com
}
Java
// Must be called on the @UiThread
if (WebViewFeature.isFeatureSupported(WebViewFeature.PRECONNECT)) {
profile.preconnect("https://www.example.com/index.html");
// This initiates a connection to the origin https://www.example.com
}
الإعداد الشائع: PrefetchParameters وPrerenderParameters
يستخدم كلّ من Prefetch وPrerender PrefetchParameters أو PrerenderParameters لتخصيص الطلب. تتيح لك هذه الفئات تقديم عناوين إضافية وتلميحات لمطابقة عناوين URL، مثل إعدادات No-Vary-Search.
Kotlin
// Isolated configuration specifically for Cache-Level Prefetching
val prefetchParams = PrefetchParameters.Builder()
.addAdditionalHeader("X-Custom-Client", "Android-App-V2")
.setExpectedNoVarySearchHeader(
NoVarySearchHeader.varyExcept(true, listOf("session_id", "click_ref"))
)
.build()
Java
PrefetchParameters prefetchParams = new PrefetchParameters.Builder()
.addAdditionalHeader("X-Custom-Header", "value")
/**
* Hint to ignore specific query parameters during cache matching.
* This allows the cache to match even if the tracking_id differs.
*/
.setExpectedNoVarySearchHeader(
NoVarySearchHeader.varyExcept(true, Arrays.asList("tracking_id"))
)
/**
* Determines if Client Hints are sent.
* NOTE: This is ignored for Prerendering API requests, which default to
* the WebView's WebSettings.getJavaScriptEnabled() value.
*/
.setJavaScriptEnabled(true)
.build();
استرجاع المحتوى مسبقًا
تنزّل عملية الجلب المُسبَق مورد HTML الرئيسي الخاص بعنوان URL وتخزّنه في ذاكرة التخزين المؤقت للشبكة الخاصة بالملف الشخصي. في WebView، يعمل Profile كحاوية لبيانات المتصفّح، بما في ذلك ملفات تعريف الارتباط وذاكرة التخزين المؤقت لبروتوكول HTTP وخدمات الخلفية. بما أنّ الجلب المسبق هو عملية على مستوى الملف الشخصي، يمكن لأي WebView مرتبط بهذا الملف الشخصي الاستفادة من الرد المخزّن مؤقتًا.
التنفيذ
لبدء عملية الجلب المسبق، استدعِ الدالة prefetchUrlAsync() على مثيل Profile. لا تتيح هذه العملية سوى استخدام مخطّط HTTPS.
Kotlin
profile.prefetchUrlAsync(
url,
prefetchParams,
cancellationSignal,
executor,
object : WebViewOutcomeReceiver<PrefetchResult, PrefetchException> {
override fun onResult(result: PrefetchResult) {
if (result.wasDuplicate()) {
// URL and No-Vary-Search permutations already exist in the cache layer
} else {
// The HTML payload has been successfully secured in the HTTP cache
}
}
override fun onError(error: PrefetchException) {
when (error) {
is PrefetchNetworkException -> {
// Isolates network layer or server-side HTTP anomalies
val code = error.httpStatusCode
// Facilitates rapid diagnosis of 4xx or 5xx server responses
}
else -> {
// Catches generalized execution failures and system constraints
}
}
}
}
)
Java
profile.prefetchUrlAsync(
url,
prefetchParams,
cancellationSignal,
executor,
new WebViewOutcomeReceiver<PrefetchResult, PrefetchException>() {
@Override
public void onResult(PrefetchResult result) {
if (result.wasDuplicate()) {
// URL and No-Vary-Search permutations already exist in the cache layer
} else {
// The HTML payload has been successfully secured in the HTTP cache
}
}
@Override
public void onError(PrefetchException error) {
if (error instanceof PrefetchNetworkException) {
// Isolates network layer or server-side HTTP anomalies
int code = ((PrefetchNetworkException) error).httpStatusCode;
// Facilitates rapid diagnosis of 4xx or 5xx server responses
} else {
// Catches generalized execution failures and system constraints
}
}
}
);
مراحل النشاط في عملية الاعتراض
يؤدي طلب الجلب المسبق في WebView إلى تغيير وقت وكيفية تشغيل shouldInterceptRequest()
الدالة الاحتياطية. بما أنّ ذلك يؤثر بشكل مباشر في إمكانية استخدام المحتوى الذي تم جلبه مسبقًا بنجاح، من المهم فهم دورة الحياة المكوّنة من خطوتَين:
1. مرحلة التخمين (طلب الجلب المسبق)
عند استدعاء prefetchUrlAsync()، ينزّل WebView مصدر HTML الرئيسي في الخلفية. يتم تخطّي shouldInterceptRequest() بالكامل لهذا الطلب الذي يتم تنفيذه في الخلفية. لا يتم تطبيق أي منطق مخصّص أو رموز مميّزة للتفويض أو عمليات إدخال في العنوان يتم التعامل معها عادةً داخل أداة الاعتراض على مصدر HTML الذي تم جلبه مسبقًا.
2. مرحلة التنقّل (تفعيل المستخدم)
عندما ينتقل التطبيق صراحةً إلى عنوان URL (على سبيل المثال، باستخدام loadUrl()) أو عندما ينقر المستخدم على رابط مطابق، يحدّد WebView ما إذا كان بإمكانه استخدام ذاكرة التخزين المؤقت التي تمّت جلبها مسبقًا:
تقييم HTML الرئيسي: سيؤدي WebView إلى تشغيل
shouldInterceptRequest()لملف HTML الرئيسي في هذه اللحظة. لعرض الصفحة بنجاح من ذاكرة التخزين المؤقت للجلب المسبق، يجب أن يعرض برنامج اعتراض الطلبات القيمةnull. في حال إرجاعWebResourceResponse، يحترم WebView أداة الاعتراض ويتجاهل ذاكرة التخزين المؤقت الخاصة بجلب البيانات المسبق.تقييم الموارد الفرعية: بعد إتاحة استخدام رمز HTML الذي تمّت جلب بياناته مسبقًا، يتم تشغيل
shouldInterceptRequest()بشكل طبيعي لجميع الموارد الفرعية اللاحقة (مثل الصور والنصوص البرمجية وCSS) المطلوبة لإنهاء عرض الصفحة.
السلوكيات الرئيسية
تتحكّم الخصائص التشغيلية وعمليات التحقّق من الأهلية التالية في كيفية بدء WebView لطلبات الجلب المسبق وإدارتها:
- أمان سلاسل المحادثات: يمكن بدء الطلبات من أي سلسلة محادثات.
- الأهلية: قبل بدء عملية الجلب، تتأكّد WebView من أنّ الطلب آمن ومناسب سياقيًا من خلال التحقّق من ما يلي:
- ملفات تعريف الارتباط الحالية: لحماية خصوصية المستخدمين ومنع حدوث آثار جانبية مشابهة لهجمات CSRF، قد تتخطى WebView عملية الجلب المسبق إذا كان الطلب يتطلّب ملفات تعريف ارتباط محدّدة مصادَق عليها يمكن أن تؤدي إلى تغيير الحالة على الخادم.
- توفّر مشغّل الخدمات: إذا كان مشغّل الخدمات يتحكّم حاليًا في نطاق عنوان URL، يمكن أن تؤجّل WebView عملية جلب البيانات إلى معالج الجلب الخاص بمشغّل الخدمات بدلاً من بدء عملية جلب مسبق عادية من الشبكة.
- توفر الخادم الوكيل: يتحقّق WebView من أنّ مسار الشبكة الحالي (بما في ذلك أي خوادم وكيل تم ضبطها) ثابت لتجنُّب تعذُّر الطلبات التخمينية في إعدادات الشبكة المعقّدة.
- إذا تعذّر بدء عملية الجلب المسبق (حتى مع توفّر مَعلمات صالحة)، يكون السبب غالبًا أنّ WebView قد حدّد أنّ طلبًا في الخلفية قد يتعارض مع جلسة المستخدم الحالية أو حالة الأمان.
- الإلغاء: استخدِم
CancellationSignalلإنهاء طلب قيد التنفيذ ومنع تخزينه مؤقتًا.
العرض المُسبَق للصفحات
تتيح عملية العرض المسبق إنشاء "محتوى ويب" مخفي لعرض صفحة بالكامل في الخلفية، بما في ذلك تنفيذ النصوص البرمجية واسترداد الموارد الفرعية. تعتمد عملية العرض المسبق على البنية الأساسية نفسها التي تعتمد عليها عملية الجلب المسبق. إذا بدأ تطبيق عملية العرض المسبق، سيجري WebView أولاً عملية جلب مسبق للردّ من أجل عرض صفحة التنقّل التي تم عرضها مسبقًا، ما يؤدي إلى تجنُّب نشاط الشبكة الزائد.
التنفيذ
التحميل المسبق هو عملية على مستوى مثيل WebView. الاتصال بـ prerenderUrlAsync()
باستخدام WebViewCompat من سلسلة التعليمات الخاصة بواجهة المستخدم
Kotlin
WebViewCompat.prerenderUrlAsync(
webView,
url,
cancellationSignal,
executor,
params,
object : PrerenderOperationCallback {
override fun onPrerenderActivated() {
// Called when the user navigates to the URL and the hidden page is swapped in
}
override fun onError(exception: Throwable) {
// exception is an instance of PrerenderException
// Handle prerender failure (for example, memory pressure or disallowed JavaScript APIs)
}
}
)
Java
WebViewCompat.prerenderUrlAsync(webView, url, cancellationSignal, executor, params, new PrerenderOperationCallback() {
@Override
public void onPrerenderActivated() {
// Called when the user navigates to the URL and the hidden page is swapped in.
}
@Override
public void onError(@NonNull Throwable exception) {
// Handle prerender failure (for example, resource constraints or disallowed APIs).
}
});
كلّ من الجلب المسبق والعرض المسبق غير متزامنَين تمامًا. يمكن استدعاء prefetchUrlAsync() من أي سلسلة تعليمات، بينما يجب بدء prerenderUrlAsync() من سلسلة واجهة المستخدم.
القيود الفنية
لتحقيق التوازن بين التنقّل الفوري وحالة النظام، يفرض WebView قيود وقت التشغيل التالية:
- ضغط الذاكرة: تلغي WebView عناوين URL التي تم عرضها مسبقًا إذا كانت ذاكرة الوصول العشوائي (RAM) في الجهاز منخفضة.
- واجهات برمجة التطبيقات غير المسموح بها: أي محاولات من JavaScript للوصول إلى واجهات برمجة تطبيقات معيّنة (مثل تشغيل الصوت أو التنبيهات) في سياق الخلفية ستؤدي فورًا إلى إنهاء العرض المسبق.
- الحدّ الأقصى لعدد المثيلات: هناك حدّ أقصى لعدد عناوين URL النشطة التي تم عرضها مسبقًا والمسموح بها لكل WebView.
مطابقة عناوين URL وNo-Vary-Search (NVS)
تتطلّب WebView خوارزمية مطابقة موثوقة لضمان عدم عرض المورد المحمَّل مسبقًا إلا عند التنقّل إلى الوجهة المقصودة.
المطابقة التامة مقابل المطابقة مع نظام التحقّق من صحة العرض
بشكلٍ تلقائي، تتطلّب عمليتا الجلب المسبق والعرض المسبق مطابقة تامة لعنوان URL. إذا كان عنوان URL الذي تم الانتقال إليه مطابقًا لعنوان URL الذي تم تحميله مسبقًا، سيتم عرضه من ذاكرة التخزين المؤقت على الفور. إذا اختلفت مَعلمات طلب البحث، سيستخدم WebView قواعد No-Vary-Search (NVS) التالية:
- التلميح: يقدّم المطوّرون
setExpectedNoVarySearchHeader()تلميحًا أثناء عملية الإعداد. إذا كان عنوان URL الذي تم الانتقال إليه يطابق عنوان URL للطلب باستثناء المَعلمات التي تم تقديم تلميحات بشأنها، سيتم حظر WebView لفترة وجيزة للانتظار إلى أن يتم تلقّي العناوين الفعلية من الخادم. - عنوان الخادم: يمثّل عنوان استجابة NVS من الخادم المرجع النهائي. إذا أكّد الخادم أنّه يجب تجاهل الاختلافات في طلب البحث، سيتم عرض التطابق من ذاكرة التخزين المؤقت. إذا لم يكن الأمر كذلك، يعود WebView إلى تحميل الشبكة الباردة.
إنّ No-Vary-Search (NVS) مخصّص للاستخدام المتقدّم، وقد لا يحتاج معظم المطوّرين إلى استخدامه لأنّهم يمرّرون عنوان URL نفسه تمامًا إلى كلّ من الجلب المُسبَق وloadUrl(). لا تكون هذه الإرشادات ضرورية إلا إذا كانت هناك اختلافات في مَعلمات طلب البحث بين عنوان URL الخاص بجلب البيانات المسبق وعنوان URL الخاص بـ loadUrl().
الإعدادات العامة
يمكنك ضبط سلوك التحميل التخميني على مستوى الملف الشخصي من خلال ضبط
PrefetchCache الحدود والحد الأقصى لعمليات العرض المسبق. يمكنك أيضًا إعادة ضبط حدود الجلب المسبق المخصّصة على الإعدادات التلقائية للنظام:
Kotlin
// Configure prefetch cache limits
profile.prefetchCache.setMaxPrefetches(10)
profile.prefetchCache.setPrefetchTtlSeconds(60)
// Reset to system defaults when needed
profile.prefetchCache.clearMaxPrefetches()
// Configure maximum active prerenders
profile.setMaxPrerenders(2)
Java
// Configure prefetch cache limits
PrefetchCache prefetchCache = profile.getPrefetchCache();
prefetchCache.setMaxPrefetches(10);
prefetchCache.setPrefetchTtlSeconds(60);
// Reset to system defaults when needed
prefetchCache.clearMaxPrefetches();
// Configure maximum active prerenders
profile.setMaxPrerenders(2);
معالجة الأخطاء والاستثناءات
تستخدِم العمليات التخمينية OutcomeReceiverCompat أو
PrerenderOperationCallback للإبلاغ عن النتائج.
الاستثناءات الأساسية
عندما يتعذّر تنفيذ عملية التحميل المبني على توقّع، يعرض المعالج أحد أنواع الاستثناءات الأساسية التالية لمساعدتك في تشخيص سيناريوهات معيّنة لحدوث الخطأ:
PrefetchException: الصنف الأساسي لجميع أخطاء الجلب المسبق غير المتزامن.PrefetchNetworkException: يشير إلى حدوث خطأ على مستوى الشبكة أو الخادم. يمكن أن يتضمّن حقلhttpStatusCode(مثل 404 أو 503) للمساعدة في تشخيص المشاكل من جهة الخادم.PrerenderException: الفئة الرئيسية لجميع الأخطاء ذات الصلة بالعرض المسبق، مثل حالات التعذّر بسبب ضغط الذاكرة أو استخدام واجهات برمجة تطبيقات غير مسموح بها (مثل تشغيل الصوت) في الخلفية.
استراتيجيات التحسين
اتّبِع هذه الاقتراحات للاستفادة إلى أقصى حدّ من مزايا التحميل المبني على توقّع مع الحفاظ على موارد النظام:
- البدء مبكرًا: ابدأ في الجلب المسبق أثناء بدء تشغيل التطبيق أو بمجرد أن يصبح من المحتمل الوصول إلى وجهة التنقّل.
- استراتيجية مدمجة: إذا كنت تجري عرضًا مسبقًا لعنوان URL في ذاكرة التخزين المؤقت للجلب المسبق، سيتم عرض عملية التنقّل المسبق من ذاكرة التخزين المؤقت هذه، ما يؤدي إلى تجنُّب طلبات الشبكة المكرّرة.
- مراقبة الحصص: تتطلّب عملية العرض المسبق الكثير من الموارد. ننصحك بتفضيل الجلب المُسبَق لعدة مرشحين محتملين، وحجز العرض المُسبَق للتنقّل الأكثر احتمالاً.
- التوافق مع المخطط: تأكَّد من أنّ جميع عناوين URL تستخدم مخطط HTTPS الإلزامي. تؤدي المخططات غير الصالحة أو المدخلات الفارغة إلى تشغيل
IllegalArgumentExceptionمتزامن.
مراجع إضافية
لمزيد من المعلومات حول تصحيح أخطاء تطبيقات الويب وتحسين أداء بدء تشغيل WebView والتعامل مع إنهاء عملية العرض، يُرجى الاطّلاع على المراجع التالية: