استخدام WebView
لتسليم تطبيق ويب
أو صفحة ويب كجزء من تطبيق عميل. الفئة WebView
هي
لفئة View
من نظام التشغيل Android تتيح
تعرض صفحات الويب كجزء من تخطيط نشاطك. ولا تشمل الحالة
الميزات المتوفرة في متصفح ويب مطور بالكامل، مثل عناصر التحكم في التنقل أو
شريط العناوين. كل ما يفعله WebView
هو عرض صفحة ويب تلقائيًا.
بإمكان "WebView
" مساعدتك في تقديم معلومات داخل تطبيقك قد تحتاج إلى
مثل اتفاقية المستخدم النهائي أو دليل المستخدم. ضمن تطبيق Android،
يمكنك إنشاء Activity
يحتوي على
WebView
، ثم استخدامه لعرض المستند المستضاف على الإنترنت.
يمكن أن يساعدك WebView
أيضًا عندما يقدّم تطبيقك بيانات للمستخدم تتطلّب
الاتصال بالإنترنت لاسترداد البيانات، مثل البريد الإلكتروني. في هذه الحالة، قد
تجد أنّه من الأسهل إنشاء WebView
في تطبيق Android يعرض
صفحة ويب تتضمّن جميع بيانات المستخدمين، بدلاً من تنفيذ طلب شبكة، ثم
تحليل البيانات وعرضها بتنسيق Android. بدلاً من ذلك، يمكنك تصميم
المُصممة للأجهزة التي تعمل بنظام التشغيل Android ثم تنفيذ
WebView
في تطبيق Android الذي يحمّل صفحة الويب
يوضّح هذا المستند كيفية بدء استخدام WebView
وكيفية ربط
JavaScript من صفحة الويب برمز جهة العميل في تطبيق Android وكيفية
معالجة التنقّل في الصفحة وكيفية إدارة النوافذ عند استخدام WebView
.
العمل مع WebView على إصدارات Android الأقدم
لاستخدام أحدث ميزات "WebView
" بأمان على الجهاز، يستخدم تطبيقك
قيد التشغيل، أضف AndroidX
مكتبة Webkit. هذه مكتبة static
يمكنك إضافتها إلى تطبيقك لاستخدام واجهات برمجة تطبيقات android.webkit
التي لا
تتوفّر لإصدارات النظام الأساسي السابقة.
أضِفه إلى ملف build.gradle
على النحو التالي:
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()
، باسم
كما هو موضح في المثال التالي:
val myWebView: WebView = findViewById(R.id.webview) myWebView.loadUrl("http://www.example.com")
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com");
إضافة WebView في onCreate()
لإضافة WebView
إلى تطبيقك بطريقة onCreate()
الخاصة بالنشاط، استخدِم بدلاً من ذلك.
بشكل مشابه لما يلي:
val myWebView = WebView(activityContext) setContentView(myWebView)
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
بعد ذلك، حمِّل الصفحة:
myWebView.loadUrl("http://www.example.com")
myWebView.loadUrl("https://www.example.com");
أو يمكنك تحميل عنوان URL من سلسلة HTML:
// 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")
// 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()
.
راجِع المثال التالي:
val myWebView: WebView = findViewById(R.id.webview) myWebView.settings.javaScriptEnabled = true
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 الاتصال به للوصول إلى الفئة.
على سبيل المثال، يمكنك تضمين الفئة التالية في تطبيق Android:
/** 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() } }
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()
، كما هو موضّح في المثال التالي:
val webView: WebView = findViewById(R.id.webview) webView.addJavascriptInterface(WebAppInterface(this), "Android")
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
.
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 } }
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
:
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
عندما ينقر المستخدم على رابط ما، يستدعي النظام الآن
shouldOverrideUrlLoading()
التي تتحقّق مما إذا كان مضيف عنوان URL مطابقًا
مجال معين، كما هو موضح في المثال السابق. إذا كان يتطابق،
تعرض الطريقة القيمة false ولا تلغي تحميل عنوان 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()
مثل
التالي:
// 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 } }
// 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
زر الرجوع
في الجهاز للتنقّل للخلف:
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) }
@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 من AndroidX AppCompat
أو الإصدارات الأحدث، يمكنك تبسيط مقتطف الرمز البرمجي السابق بشكل أكبر:
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack() } }
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack(); } }
الطريقة canGoBack()
على "صواب" إذا كان هناك سجل صفحة ويب يمكن للمستخدم زيارته. وبالمثل، يمكنك استخدام canGoForward()
للتحقّق مما إذا كان هناك سجلّ للرسائل المُرسَلة. إذا لم تقم بإجراء هذا الفحص، فحينئذٍ
بعد وصول المستخدِم إلى نهاية السجلّ، ينفذ goBack()
وgoForward()
لا شيء.
التعامل مع التغييرات في إعدادات الجهاز
أثناء بيئة التشغيل، تحدث تغييرات حالة النشاط عند ضبط الجهاز
التغييرات، مثل التغييرات التي تحدث عند تدوير الجهاز أو تجاهل أحد محرِّري أساليب الإدخال
(IME). تؤدي هذه التغييرات إلى إتلاف نشاط عنصر WebView
وإنشاء
نشاط جديد، ما يؤدي أيضًا إلى إنشاء عنصر WebView
جديد يحمِّل
عنوان URL للعنصر الذي تم إتلافه. لتعديل السلوك التلقائي للنشاط، يمكنك
تغيير طريقة تعامله مع تغييرات orientation
في البيان. لمزيد من المعلومات
حول التعامل مع تغييرات الإعدادات أثناء التشغيل، يُرجى الاطّلاع على مقالة التعامل مع
تغييرات الإعدادات.
إدارة النوافذ
يتم تلقائيًا تجاهل طلبات فتح نوافذ جديدة. هذا صحيح سواء قاموا
يتم فتحها بواسطة JavaScript أو من خلال السمة المستهدفة في رابط. يمكنك تخصيص
WebChromeClient
لتحديد السلوك الذي تريده عند فتح عدة
نوافذ.
للحفاظ على أمان تطبيقك، من الأفضل منع فتح النوافذ المنبثقة والنوافذ الجديدة. الطريقة الأكثر أمانًا لتنفيذ هذا السلوك هي تمرير "true"
إلى
setSupportMultipleWindows()
ولكن لا تتجاهل
onCreateWindow()
التي تعتمد عليها setSupportMultipleWindows()
. يمنع هذا المنطق تحميل أي
صفحة تستخدم target="_blank"
في روابطها.