استخدِم WebView لتقديم تطبيق ويب أو صفحة ويب كجزء من تطبيق عميل. فئة WebView هي امتداد لفئة View في Android التي تتيح لك عرض صفحات الويب كجزء من تنسيق نشاطك. ولا يتضمّن ميزات متصفّح الويب الكامل، مثل عناصر التحكّم في التنقّل أو شريط العناوين. كل ما يفعله WebView، بشكل تلقائي، هو عرض
صفحة ويب.
يمكن أن يساعدك WebView في توفير معلومات في تطبيقك قد تحتاج إلى
تحديثها، مثل اتفاقية المستخدم النهائي أو دليل المستخدم. في تطبيق Android،
يمكنك إنشاء Activity يحتوي على
WebView، ثم استخدامه لعرض المستند المستضاف على الإنترنت.
يمكن أن يساعد WebView أيضًا عندما يوفّر تطبيقك بيانات للمستخدم تتطلّب
اتصالاً بالإنترنت لاسترداد البيانات، مثل البريد الإلكتروني. في هذه الحالة، قد
يكون من الأسهل إنشاء WebView في تطبيق Android يعرض صفحة ويب
تتضمّن جميع بيانات المستخدم، بدلاً من إجراء طلب شبكة، ثم
تحليل البيانات وعرضها في تنسيق Android. بدلاً من ذلك، يمكنك تصميم صفحة ويب مخصّصة للأجهزة التي تعمل بنظام التشغيل Android، ثم تنفيذ WebView في تطبيق Android الذي يحمّل صفحة الويب.
يوضّح هذا المستند كيفية بدء استخدام WebView، وكيفية ربط
JavaScript من صفحة الويب بالرمز البرمجي من جهة العميل في تطبيق Android، وكيفية
التعامل مع التنقّل في الصفحة، وكيفية إدارة النوافذ عند استخدام WebView.
استخدام WebView في الإصدارات القديمة من Android
لاستخدام أحدث إمكانات WebView بأمان على الجهاز الذي يعمل عليه تطبيقك، أضِف مكتبة Jetpack Webkit. هذه مكتبة ثابتة يمكنك إضافتها إلى تطبيقك لاستخدام واجهات برمجة تطبيقات android.webkit غير المتاحة لإصدارات النظام الأساسي السابقة.
أضِفها إلى ملف build.gradle على النحو التالي:
Kotlin
dependencies { implementation("androidx.webkit:webkit:1.8.0") }
أنيق
dependencies { implementation ("androidx.webkit:webkit:1.8.0") }
يمكنك الاطّلاع على مثال WebView على GitHub لمزيد من التفاصيل.
إضافة WebView إلى تطبيقك
لإضافة WebView إلى تطبيقك، يمكنك تضمين عنصر <WebView> في تنسيق النشاط أو ضبط نافذة Activity بالكامل على أنّها WebView في onCreate.
إضافة WebView في تنسيق النشاط
لإضافة WebView إلى تطبيقك في التنسيق، أضِف الرمز التالي إلى ملف XML لتنسيق النشاط:
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" />
لتحميل صفحة ويب في WebView، استخدِم loadUrl، كما هو موضّح في المثال التالي:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.loadUrl("http://www.example.com")
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com");
إضافة WebView في onCreate()
لإضافة WebView إلى تطبيقك في إجراء onCreate() الخاص بالنشاط بدلاً من ذلك، استخدِم
منطقًا مشابهًا لما يلي:
Kotlin
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
بعد ذلك، حمِّل الصفحة:
Kotlin
myWebView.loadUrl("http://www.example.com")
Java
myWebView.loadUrl("https://www.example.com");
أو تحميل عنوان URL من سلسلة HTML:
Kotlin
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. val unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING) myWebView.loadData(encodedHtml, "text/html", "base64")
Java
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. String unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING); myWebView.loadData(encodedHtml, "text/html", "base64");
يجب أن يكون تطبيقك متصلاً بالإنترنت. للحصول على إمكانية الوصول إلى الإنترنت، اطلب إذن
INTERNET في ملف البيان، كما هو موضّح في المثال
التالي:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
يمكنك تخصيص WebView من خلال تنفيذ أيّ مما يلي:
- تفعيل وضع ملء الشاشة باستخدام
WebChromeClientيتم أيضًا استدعاء هذه الفئة عندما يحتاجWebViewإلى إذن لتغيير واجهة مستخدم التطبيق المضيف، مثل إنشاء النوافذ أو إغلاقها أو إرسال مربّعات حوار JavaScript إلى المستخدم. لمزيد من المعلومات حول تصحيح الأخطاء في هذا السياق، يُرجى الاطّلاع على تصحيح أخطاء تطبيقات الويب. - التعامل مع الأحداث التي تؤثر في عرض المحتوى، مثل الأخطاء في عمليات إرسال النماذج أو التنقّل باستخدام
WebViewClientيمكنك أيضًا استخدام هذه الفئة الفرعية لاعتراض تحميل عنوان URL. - تفعيل JavaScript من خلال تعديل
WebSettings - استخدام JavaScript للوصول إلى عناصر إطار عمل Android التي تم إدخالها
في
WebView
استخدام JavaScript في WebView
إذا كانت صفحة الويب التي تريد تحميلها في WebView تستخدم JavaScript، عليك تفعيل JavaScript في WebView. بعد تفعيل JavaScript، يمكنك إنشاء واجهات بين رمز تطبيقك ورمز JavaScript.
تفعيل JavaScript
تكون JavaScript غير مفعَّلة في WebView تلقائيًا. يمكنك تفعيلها من خلال
WebSettings المرفق بـ WebView. يمكنك استرداد WebSettings باستخدام
getSettings، ثم تفعيل JavaScript باستخدام
setJavaScriptEnabled.
انظر المثال التالي:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.settings.javaScriptEnabled = true
Java
WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true);
يتيح لك WebSettings الوصول إلى مجموعة متنوعة من الإعدادات الأخرى التي قد تكون مفيدة لك. على سبيل المثال، إذا كنت تطوّر تطبيق ويب مصمّمًا
خصيصًا لـ WebView في تطبيق Android، يمكنك تحديد سلسلة وكيل مستخدم
مخصّصة باستخدام setUserAgentString، ثم طلب وكيل المستخدم
المخصّص في صفحة الويب للتحقّق من أنّ العميل الذي يطلب صفحة الويب هو
تطبيق Android.
ربط رمز JavaScript برمز Android
عند تطوير تطبيق ويب مصمَّم خصيصًا لـ WebView
في تطبيق Android، يمكنك إنشاء واجهات بين رمز JavaScript ورمز Android
من جهة العميل. على سبيل المثال، يمكن لرمز JavaScript استدعاء طريقة في رمز Android لعرض Dialog، بدلاً من استخدام دالة alert() في JavaScript.
لربط واجهة جديدة بين رمز JavaScript ورمز Android، يمكنك استدعاء
addJavascriptInterface، مع تمرير مثيل فئة لربطه برمز
JavaScript واسم واجهة يمكن لرمز JavaScript استدعاؤه للوصول إلى
الفئة.
لمزيد من المعلومات حول التواصل بين JavaScript والرموز البرمجية الأصلية، بما في ذلك واجهات برمجة التطبيقات الأكثر حداثة وأمانًا، يُرجى الاطّلاع على مقالة الوصول إلى واجهات برمجة التطبيقات الأصلية باستخدام JSBridge.
على سبيل المثال، يمكنك تضمين الفئة التالية في تطبيق Android:
Kotlin
/** Instantiate the interface and set the context. */ class WebAppInterface(private val mContext: Context) { /** Show a toast from the web page. */ @JavascriptInterface fun showToast(toast: String) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show() } }
Java
public class WebAppInterface { Context mContext; /** Instantiate the interface and set the context. */ WebAppInterface(Context c) { mContext = c; } /** Show a toast from the web page. */ @JavascriptInterface public void showToast(String toast) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); } }
في هذا المثال، تتيح فئة WebAppInterface لصفحة الويب إنشاء رسالة Toast باستخدام الإجراء showToast().
يمكنك ربط هذه الفئة بـ JavaScript الذي يتم تشغيله في WebView باستخدام
addJavascriptInterface()، كما هو موضّح في المثال التالي:
Kotlin
val webView: WebView = findViewById(R.id.webview) webView.addJavascriptInterface(WebAppInterface(this), "Android")
Java
WebView webView = (WebView) findViewById(R.id.webview); webView.addJavascriptInterface(new WebAppInterface(this), "Android");
يؤدي ذلك إلى إنشاء واجهة باسم Android لـ JavaScript الذي يتم تشغيله في
WebView. في هذه المرحلة، يمكن لتطبيق الويب الوصول إلى
فئة WebAppInterface. على سبيل المثال، إليك بعض رموز HTML وJavaScript التي تنشئ رسالة إشعار مؤقت باستخدام الواجهة الجديدة عندما ينقر المستخدم على زر:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script>
لا حاجة إلى إعداد واجهة Android من JavaScript. ويجعلها WebView متاحة تلقائيًا لصفحة الويب. لذلك، عندما ينقر المستخدم على الزر، تستخدم الدالة showAndroidToast() واجهة Android لاستدعاء الطريقة WebAppInterface.showToast().
التعامل مع التنقّل في الصفحة
عندما ينقر المستخدم على رابط من صفحة ويب في WebView، يشغّل Android تلقائيًا
تطبيقًا يعالج عناوين URL. عادةً ما يفتح متصفّح الويب التلقائي
ويحمّل عنوان URL المقصود. ومع ذلك، يمكنك إلغاء هذا السلوك في WebView لفتح الروابط ضمن WebView. يمكنك بعد ذلك السماح للمستخدم بالتنقّل للخلف وللأمام في سجلّ صفحات الويب الذي يحتفظ به WebView.
لفتح الروابط التي ينقر عليها المستخدم، يجب توفير WebViewClient لـ WebView
باستخدام setWebViewClient. يتم تحميل جميع الروابط التي ينقر عليها المستخدم في
WebView. إذا أردت التحكّم بشكل أكبر في مكان تحميل الرابط الذي تم النقر عليه، يمكنك إنشاء WebViewClient خاص بك يتجاوز طريقة shouldOverrideUrlLoading. يفترض المثال التالي أنّ MyWebViewClient هي فئة داخلية
من Activity.
Kotlin
private class MyWebViewClient : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { if (Uri.parse(url).host == "www.example.com") { // This is your website, so don't override. Let your WebView load // the page. return false } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { startActivity(this) } return true } }
Java
private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { if ("www.example.com".equals(request.getUrl().getHost())) { // This is your website, so don't override. Let your WebView load the // page. return false; } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); startActivity(intent); return true; } }
بعد ذلك، أنشئ مثيلاً من WebViewClient الجديد هذا لـ WebView:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
الآن، عندما ينقر المستخدم على رابط، يستدعي النظام الطريقة shouldOverrideUrlLoading التي تتحقّق مما إذا كان مضيف عنوان URL يتطابق مع نطاق معيّن، كما هو محدّد في المثال السابق. إذا كان هناك تطابق، ستعرض الطريقة القيمة "خطأ" ولن تلغي تحميل عنوان URL. ويسمح لـ WebView بتحميل عنوان URL كالمعتاد.
إذا لم يتطابق مضيف عنوان URL، يتم إنشاء Intent لتشغيل Activity التلقائي لمعالجة عناوين URL، والذي يتم تحليله إلى متصفّح الويب التلقائي للمستخدم.
التعامل مع عناوين URL المخصّصة
يطبّق "WebView" قيودًا عند طلب الموارد وحلّ الروابط
التي تستخدم مخطّط URL مخصّصًا. على سبيل المثال، إذا نفّذت عمليات استدعاء مثل
shouldOverrideUrlLoading أو shouldInterceptRequest،
سيستدعيها WebView لعناوين URL الصالحة فقط.
على سبيل المثال، قد لا يستدعي WebView طريقة shouldOverrideUrlLoading
للروابط مثل:
<a href="showProfile">Show Profile</a>
يتم التعامل مع عناوين URL غير الصالحة، مثل العنوان الموضّح في المثال السابق، بشكل غير متّسق في WebView، لذا ننصح باستخدام عنوان URL منسَّق بشكل جيد بدلاً من ذلك.
يمكنك استخدام مخطّط مخصّص أو عنوان URL يستخدم HTTPS لنطاق تتحكّم فيه مؤسستك.
بدلاً من استخدام سلسلة بسيطة في رابط، كما في المثال السابق، يمكنك استخدام مخطّط مخصّص مثل ما يلي:
<a href="example-app:showProfile">Show Profile</a>
يمكنك بعد ذلك معالجة عنوان URL هذا في طريقة shouldOverrideUrlLoading على النحو التالي:
Kotlin
// The URL scheme must be non-hierarchical, meaning no trailing slashes. const val APP_SCHEME = "example-app:" override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { return if (url?.startsWith(APP_SCHEME) == true) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8") respondToData(urlData) true } else { false } }
Java
// The URL scheme must be non-hierarchical, meaning no trailing slashes. private static final String APP_SCHEME = "example-app:"; @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith(APP_SCHEME)) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8"); respondToData(urlData); return true; } return false; }
تم تصميم واجهة برمجة التطبيقات shouldOverrideUrlLoading بشكل أساسي لتشغيل الأهداف
لعناوين URL معيّنة. عند تنفيذها، تأكَّد من عرض false لعناوين URL
التي يعالجها WebView. ومع ذلك، لا يقتصر الأمر على إطلاق الأهداف. يمكنك استبدال النوايا الخاصة بالإطلاق بأي سلوك مخصّص في عيّنات التعليمات البرمجية السابقة.
التنقّل في سجلّ صفحات الويب
عندما يتجاوز WebView تحميل عنوان URL، فإنه يجمع تلقائيًا
سجلّ صفحات الويب التي تمت زيارتها. يمكنك التنقّل للخلف وللأمام في السجلّ باستخدام goBack وgoForward.
على سبيل المثال، يوضّح ما يلي كيف يمكن لـ Activity استخدام زر الرجوع في الجهاز للانتقال إلى الخلف:
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { // Check whether the key event is the Back button and if there's history. if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) { myWebView.goBack() return true } // If it isn't the Back button or there isn't web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event) }
Java
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Check whether the key event is the Back button and if there's history. if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) { myWebView.goBack(); return true; } // If it isn't the Back button or there's no web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event); }
إذا كان تطبيقك يستخدم الإصدار 1.6.0 أو إصدارًا أحدث من Jetpack AppCompat، يمكنك تبسيط المقتطف السابق أكثر:
Kotlin
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack() } }
Java
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack(); } }
تعرض الطريقة canGoBack القيمة "صحيح" إذا كان هناك سجلّ لصفحات الويب التي زارها المستخدم. وبالمثل، يمكنك استخدام canGoForward للتحقّق مما إذا كان هناك سجلّ تصفُّح للأمام. إذا لم تُجرِ هذا التحقّق، لن يؤدي استخدام goBack وgoForward إلى أي نتيجة بعد وصول المستخدم إلى نهاية السجلّ.
للاحتفاظ بسجلّ التنقّل في جميع عمليات إعادة إنشاء النشاط أو استعادة العمليات في الخلفية، استخدِم saveState لتسلسل سجلّ التنقّل في WebView إلى Bundle، وrestoreState لاستعادته.
للحصول على إرشادات حول كيفية إدارة حدود حجم الحالة المحفوظة بأمان وتجنُّب
TransactionTooLargeException، يُرجى الاطّلاع على مقالة إدارة حالة WebView بكفاءة.
التعامل مع التغييرات في إعدادات الجهاز
أثناء وقت التشغيل، تحدث تغييرات في حالة النشاط عند تغيير إعدادات الجهاز، مثل تدوير المستخدمين للجهاز أو إغلاق محرِّر أسلوب الإدخال (IME). تؤدي هذه التغييرات إلى تدمير نشاط عنصر WebView وإنشاء نشاط جديد، ما يؤدي أيضًا إلى إنشاء عنصر WebView جديد يحمّل عنوان URL الخاص بالعنصر المدمَّر. يمكنك استخدام saveState ضمن
onSaveInstanceState() وrestoreState عند إعادة الإنشاء لاستعادة
سياق التنقّل للمستخدم. للاطّلاع على استراتيجيات إدارة حجم الحالة بأمان، يُرجى مراجعة مقالة إدارة حالة WebView بكفاءة.
لتعديل الإعدادات التلقائية لنشاطك، يمكنك تغيير طريقة تعامله مع
تغييرات orientation في البيان. لمزيد من المعلومات حول التعامل مع تغييرات الإعدادات أثناء وقت التشغيل، يُرجى الاطّلاع على التعامل مع تغييرات الإعدادات.
إدارة النوافذ
يتم تجاهل طلبات فتح نوافذ جديدة تلقائيًا. وينطبق ذلك سواء تم فتحها من خلال JavaScript أو من خلال سمة الهدف في رابط. يمكنك تخصيص
"WebChromeClient" لتوفير سلوكك الخاص لفتح نوافذ
متعددة.
للحفاظ على أمان تطبيقك، من الأفضل منع فتح النوافذ المنبثقة والنوافذ الجديدة. الطريقة الأكثر أمانًا لتنفيذ هذا السلوك هي تمرير "true" إلى
setSupportMultipleWindows ولكن بدون إلغاء طريقة
onCreateWindow التي يعتمد عليها setSupportMultipleWindows().
يمنع هذا المنطق تحميل أي صفحة تستخدم target="_blank" في روابطها.
إدارة الذاكرة والأداء
بما أنّ WebView يعمل على محرّك مستند إلى Chromium مع عمليات منفصلة ورموز برمجية أصلية، يكون معدّل استخدام الذاكرة الأساسي أعلى من طرق العرض العادية في Android.
تُعد إعادة استخدام مثيلات WebView وإتلافها بشكل صحيح أمرًا ضروريًا
للحفاظ على استقرار التطبيق.
لمزيد من المعلومات حول كيفية تشخيص استهلاك الذاكرة في تطبيقك وتحسينه عند استخدام محتوى على الويب، يُرجى الاطّلاع على مقالة إدارة ذاكرة WebView وتشخيصها.