يوفر نظام التشغيل Android العديد من واجهات برمجة التطبيقات لمساعدتك في إدارة
WebView
العناصر التي تعرض محتوى الويب في تطبيقك.
توضّح هذه الصفحة كيفية استخدام واجهات برمجة التطبيقات هذه للتعامل مع عناصر WebView
بشكل أكثر فعالية، ما يؤدي إلى تحسين ثبات تطبيقك وأمانه.
Version API
بدءًا من الإصدار 7.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 24)، يمكن للمستخدمين الاختيار من بين عدة حِزم مختلفة لعرض محتوى الويب في عنصر WebView.
تتضمّن مكتبة Jetpack Webkit الطريقة getCurrentWebViewPackage() لاسترداد المعلومات المتعلقة بالحزمة التي تعرض محتوى الويب في تطبيقك. وتكون هذه الطريقة مفيدة عند تحليل الأخطاء التي تحدث فقط عندما يحاول تطبيقك عرض محتوى الويب باستخدام تنفيذ WebView لحزمة معيّنة.
لاستخدام هذه الطريقة، أضِف المنطق الموضّح في مقتطف الرمز التالي:
Kotlin
val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext) Log.d("MY_APP_TAG", "WebView version: ${webViewPackageInfo.versionName}")
Java
PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext); Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);
خدمة "التصفّح الآمن من Google"
لتوفير تجربة تصفّح أكثر أمانًا للمستخدمين، تتحقّق WebViewالكائنات من عناوين URL باستخدام
التصفّح الآمن من Google،
ما يتيح لتطبيقك عرض تحذير للمستخدمين عند محاولة الانتقال إلى
موقع إلكتروني غير آمن قد يكون ضارًا.
على الرغم من أنّ القيمة التلقائية EnableSafeBrowsing هي true، قد تحتاج في بعض الحالات إلى تفعيل ميزة "التصفّح الآمن" بشكل مشروط أو إيقافها. يتيح نظام التشغيل Android 8.0 (مستوى واجهة برمجة التطبيقات 26) والإصدارات الأحدث استخدام setSafeBrowsingEnabled() لتبديل ميزة "التصفّح الآمن" لكائن WebView فردي.
إذا أردت إيقاف عمليات التحقّق التي يجريها التصفُّح الآمن لجميع عناصر WebView، أضِف عنصر <meta-data> التالي إلى ملف البيان الخاص بتطبيقك:
<manifest> <application> <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" /> ... </application> </manifest>
تحديد الإجراءات الآلية
عندما تحاول إحدى حالات WebView تحميل صفحة صنّفها Google على أنّها تهديد معروف، تعرض WebView تلقائيًا صفحة بينية تحذّر المستخدمين من التهديد المعروف. تتيح هذه الشاشة للمستخدمين خيار تحميل عنوان URL على أي حال أو الرجوع إلى صفحة سابقة آمنة.
إذا كنت تستهدف الإصدار 8.1 من نظام التشغيل Android (المستوى 27 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكنك تحديد كيفية استجابة تطبيقك لتهديد معروف بطريقة آلية من خلال ما يلي:
- يمكنك التحكّم في ما إذا كان تطبيقك يبلّغ ميزة "التصفّح الآمن" عن التهديدات المعروفة.
- يمكنك ضبط تطبيقك على تنفيذ إجراء معيّن تلقائيًا، مثل الرجوع إلى الوضع الآمن، في كل مرة يصادف فيها عنوان URL مصنّفًا على أنّه تهديد معروف.
توضّح مقتطفات الرمز التالية كيفية توجيه مثيلات WebView في تطبيقك إلى الرجوع دائمًا إلى الوضع الآمن بعد مواجهة تهديد معروف:
MyWebActivity.java
Kotlin
private lateinit var superSafeWebView: WebView private var safeBrowsingIsInitialized: Boolean = false // ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) superSafeWebView = WebView(this) superSafeWebView.webViewClient = MyWebViewClient() safeBrowsingIsInitialized = false if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.startSafeBrowsing(this, ValueCallback<Boolean> { success -> safeBrowsingIsInitialized = true if (!success) { Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!") } }) } }
Java
private WebView superSafeWebView; private boolean safeBrowsingIsInitialized; // ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); superSafeWebView = new WebView(this); superSafeWebView.setWebViewClient(new MyWebViewClient()); safeBrowsingIsInitialized = false; if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.startSafeBrowsing(this, new ValueCallback<Boolean>() { @Override public void onReceiveValue(Boolean success) { safeBrowsingIsInitialized = true; if (!success) { Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!"); } } }); } }
MyWebViewClient.java
Kotlin
class MyWebViewClient : WebViewClientCompat() { // Automatically go "back to safety" when attempting to load a website that // Google identifies as a known threat. An instance of WebView calls this // method only after Safe Browsing is initialized, so there's no conditional // logic needed here. override fun onSafeBrowsingHit( view: WebView, request: WebResourceRequest, threatType: Int, callback: SafeBrowsingResponseCompat ) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { callback.backToSafety(true) Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show() } } }
Java
public class MyWebViewClient extends WebViewClientCompat { // Automatically go "back to safety" when attempting to load a website that // Google identifies as a known threat. An instance of WebView calls this // method only after Safe Browsing is initialized, so there's no conditional // logic needed here. @Override public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponseCompat callback) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { callback.backToSafety(true); Toast.makeText(view.getContext(), "Unsafe web page blocked.", Toast.LENGTH_LONG).show(); } } }
HTML5 Geolocation API
بالنسبة إلى التطبيقات التي تستهدف الإصدار 6.0 من نظام التشغيل Android (المستوى 23 من واجهة برمجة التطبيقات) والإصدارات الأحدث، لا تتوفّر واجهة برمجة التطبيقات للمواقع الجغرافية إلا على المصادر الآمنة، مثل HTTPS. ويتم تلقائيًا رفض أي طلب إلى Geolocation API من مصادر غير آمنة بدون استدعاء طريقة onGeolocationPermissionsShowPrompt() المقابلة.
إيقاف جمع المقاييس
يمكن WebView تحميل بيانات تشخيصية بدون الكشف عن الهوية إلى Google عندما يوافق المستخدم على ذلك. يتم جمع البيانات على مستوى كل تطبيق لكل تطبيق ينشئ WebView. ويمكنك إيقاف هذه الميزة عن طريق إنشاء العلامة التالية في عنصر <application> في ملف البيان:
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" /> </application> </manifest>
لا يتم تحميل البيانات من تطبيق إلا إذا وافق المستخدم ولم يوقف التطبيق هذه الميزة. لمزيد من المعلومات حول إيقاف ميزة إعداد تقارير بيانات التشخيص، يمكنك الاطّلاع على خصوصية المستخدم في ميزة إعداد التقارير في WebView.
Termination Handling API
تتعامل واجهة برمجة التطبيقات Termination Handling API مع الحالات التي تختفي فيها عملية العرض الخاصة بأحد عناصر
WebView
، إما لأنّ النظام ينهي عملية العرض لاستعادة
الذاكرة اللازمة أو لأنّ عملية العرض تتعطّل. باستخدام واجهة برمجة التطبيقات هذه، يمكنك السماح لتطبيقك بمواصلة التنفيذ، حتى إذا تم إيقاف عملية العرض.
إذا تعذّر عرض صفحة ويب معيّنة أثناء تحميلها، قد تؤدي محاولة تحميل الصفحة نفسها مرة أخرى إلى أن يعرض عنصر WebView جديد السلوك نفسه المتعلق بتعذّر العرض.
يوضّح مقتطف الرمز التالي كيفية استخدام واجهة برمجة التطبيقات هذه ضمن Activity:
Kotlin
inner class MyRendererTrackingWebViewClient : WebViewClient() { private var mWebView: WebView? = null override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean { if (!detail.didCrash()) { // Renderer is killed because the system ran out of memory. The app // can recover gracefully by creating a new WebView instance in the // foreground. Log.e("MY_APP_TAG", ("System killed the WebView rendering process " + "to reclaim memory. Recreating...")) mWebView?.also { webView -> val webViewContainer: ViewGroup = findViewById(R.id.my_web_view_container) webViewContainer.removeView(webView) webView.destroy() mWebView = null } // By this point, the instance variable "mWebView" is guaranteed to // be null, so it's safe to reinitialize it. return true // The app continues executing. } // Renderer crashes because of an internal error, such as a memory // access violation. Log.e("MY_APP_TAG", "The WebView rendering process crashed!") // In this example, the app itself crashes after detecting that the // renderer crashed. If you handle the crash more gracefully and let // your app continue executing, you must destroy the current WebView // instance, specify logic for how the app continues executing, and // return "true" instead. return false } }
Java
public class MyRendererTrackingWebViewClient extends WebViewClient { private WebView mWebView; @Override public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { if (!detail.didCrash()) { // Renderer is killed because the system ran out of memory. The app // can recover gracefully by creating a new WebView instance in the // foreground. Log.e("MY_APP_TAG", "System killed the WebView rendering process " + "to reclaim memory. Recreating..."); if (mWebView != null) { ViewGroup webViewContainer = (ViewGroup) findViewById(R.id.my_web_view_container); webViewContainer.removeView(mWebView); mWebView.destroy(); mWebView = null; } // By this point, the instance variable "mWebView" is guaranteed to // be null, so it's safe to reinitialize it. return true; // The app continues executing. } // Renderer crashes because of an internal error, such as a memory // access violation. Log.e("MY_APP_TAG", "The WebView rendering process crashed!"); // In this example, the app itself crashes after detecting that the // renderer crashed. If you handle the crash more gracefully and let // your app continue executing, you must destroy the current WebView // instance, specify logic for how the app continues executing, and // return "true" instead. return false; } }
Renderer Importance API
عندما WebView كائنات
تعمل في
وضع العمليات المتعددة، يتوفّر لك بعض المرونة في طريقة تعامل تطبيقك مع
حالات نقص الذاكرة. يمكنك استخدام Renderer Importance API، الذي تم طرحه في
Android 8.0، لضبط سياسة أولوية للعارض الذي تم تعيينه لكائن
WebView معيّن. على وجه الخصوص، قد تحتاج إلى أن يستمر الجزء الرئيسي من
تطبيقك في التنفيذ عند إيقاف عارض يعرض كائنات
WebView في تطبيقك. يمكنك إجراء ذلك، على سبيل المثال، إذا كنت
تتوقّع عدم عرض الكائن WebView لفترة طويلة حتى يتمكّن
النظام من استرداد الذاكرة التي كان يستخدمها العارض.
يوضّح مقتطف الرمز التالي كيفية تحديد أولوية لعملية العرض المرتبطة بعناصر WebView في تطبيقك:
Kotlin
val myWebView: WebView = ... myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)
Java
WebView myWebView; myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
في هذا المقتطف تحديدًا، تكون أولوية أداة العرض مماثلة للأولوية التلقائية للتطبيق أو مرتبطة بها. ويؤدي الوسيط true إلى خفض أولوية أداة العرض إلى RENDERER_PRIORITY_WAIVED عندما يصبح العنصر WebView المرتبط غير مرئي. بعبارة أخرى، تشير الوسيطة true إلى أنّ تطبيقك لا يهمّه ما إذا كان النظام سيُبقي عملية العرض قيد التشغيل. في الواقع، يؤدي مستوى الأولوية المنخفض هذا إلى زيادة احتمالية إنهاء عملية العرض في حالات نقص الذاكرة.
لمزيد من المعلومات عن طريقة تعامل النظام مع حالات نقص الذاكرة، يُرجى الاطّلاع على العمليات ودورة حياة التطبيق.