Intent
هو كائن مراسلة يمكنك استخدامه لطلب إجراء من مكوِّن تطبيق آخر.
على الرغم من أنّ ملفات Intent تسهّل التواصل بين المكوّنات بعدة طرق، هناك ثلاث
حالات استخدام أساسية:
- بدء نشاط
يمثّل
Activity
شاشة واحدة في تطبيق. يمكنك بدء مثيل جديد لعنصرActivity
من خلال تمريرIntent
إلىstartActivity()
. تصف السمةIntent
النشاط المطلوب بدؤه وتحمل أي بيانات ضرورية.إذا أردت تلقّي نتيجة من النشاط عند الانتهاء، يمكنك طلب
startActivityForResult()
. يتلقّى نشاطك النتيجة على شكل كائنIntent
منفصل في استدعاءonActivityResult()
لنشاطك. لمزيد من المعلومات، يُرجى الاطّلاع على دليل الأنشطة. - بدء خدمة
Service
هو مكوّن ينفِّذ العمليات في الخلفية بدون واجهة مستخدم. باستخدام الإصدار 5.0 من نظام التشغيل Android (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك بدء خدمة باستخدامJobScheduler
. لمزيد من المعلومات حولJobScheduler
، يمكنك الاطّلاع علىAPI-reference documentation
الخاصة به.بالنسبة إلى الإصدارات الأقدم من Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، يمكنك بدء خدمة باستخدام methods من فئة
Service
. يمكنك بدء خدمة لإجراء عملية لمرة واحدة (مثل تنزيل ملف) من خلال تمريرIntent
إلىstartService()
. يصفIntent
الخدمة التي سيتم تشغيلها ويحمل أي بيانات ضرورية.إذا تم تصميم الخدمة باستخدام واجهة بين العميل والخادم، يمكنك الربط بالخدمة من مكوّن آخر عن طريق تمرير
Intent
إلىbindService()
. لمزيد من المعلومات، يُرجى الاطّلاع على دليل الخدمات. - إرسال بث
البث هو رسالة يمكن لأي تطبيق تلقّيها. يُرسِل النظام محتوًى مختلفًا للبثّ لأحداث النظام، مثل بدء تشغيل النظام أو بدء شحن الجهاز. يمكنك إرسال بث إلى تطبيقات أخرى من خلال تمرير
Intent
إلىsendBroadcast()
أوsendOrderedBroadcast()
.
توضّح بقية هذه الصفحة آلية عمل النوايا وكيفية استخدامها. للاطّلاع على معلومات ذات صلة، يُرجى الاطّلاع على مقالتَي التفاعل مع التطبيقات الأخرى ومشاركة المحتوى.
أنواع الأهداف
هناك نوعان من النوايا:
- تحدِّد المقصودات الصريحة المكوّن الذي سيلبّي المقصود من تطبيق معيّن، وذلك من خلال تحديد
ComponentName
كامل. ستستخدم عادةً هدفًا صريحًا لبدء مكون في تطبيقك الخاص، لأنك تعرف اسم فئة النشاط أو الخدمة التي تريد تشغيلها. على سبيل المثال، يمكنك بدء نشاط جديد في تطبيقك استجابةً للإجراء الذي يتّخذه المستخدم، أو بدء خدمة لتنزيل ملف في الخلفية. - لا تحدِّد الأهداف الضمنية اسم مكوّن معيّنًا، بل تحدِّد بدلاً من ذلك إجراءً عامًا لإجرائه، ما يسمح لمكوّن من تطبيق آخر بتنفيذه. فمثلاً، إذا كنت تريد أن تعرض للمستخدم موقعًا جغرافيًا على الخريطة، يمكنك استخدام نية ضمنية لطلب عرض موقع جغرافي محدّد على الخريطة من خلال تطبيق آخر مؤهَّل.
يوضّح الشكل 1 كيفية استخدام النية عند بدء نشاط. عندما يُسمّي عنصر
Intent
مكوّن نشاط معيّنًا بشكل صريح، يبدأ النظام
هذا المكوّن على الفور.
عند استخدام هدف ضمني، يعثر نظام Android على المكوّن المناسب للبدء
من خلال مقارنة محتوى الغرض مع فلاتر الأهداف التي تم تعريفها في ملف البيان الخاص بالتطبيقات الأخرى
على الجهاز. إذا تطابق الغرض مع فلتر غرض، يبدأ النظام هذا المكوّن ويرسله
كائن Intent
. إذا كانت عدّة فلاتر أهداف متوافقة،
يعرض النظام مربّع حوار حتى يتمكّن المستخدم من اختيار التطبيق الذي يريد استخدامه.
فلتر الأهداف هو تعبير في ملف بيان التطبيق يحدد نوع الأهداف التي يرغب المكوِّن في تلقيها. على سبيل المثال، من خلال الإعلان عن فلتر أهداف لنشاط معيّن، يمكنك السماح للتطبيقات الأخرى ببدء نشاطك مباشرةً باستخدام نوع معيّن من الأهداف. وبالمثل، إذا لم تحدِّد أي فلاتر أهداف لنشاط معيّن، لا يمكن بدؤه إلا باستخدام هدف صريح.
تنبيه: لضمان أمان تطبيقك، يُرجى دائمًا
استخدام نية صريحة عند بدء استخدام Service
وعدم
تعريف فلاتر الأهداف لخدماتك. يشكّل استخدام نية ضمنية لبدء خدمة خطرًا على
الأمن لأنّه لا يمكنك التأكّد من الخدمة التي ستستجيب للنية،
ولا يمكن للمستخدم معرفة الخدمة التي يتم تشغيلها. بدءًا من Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، يعرض النظام استثناءً في حال استدعاء الدالة bindService()
لغرض ضمني.
إنشاء نية
يحمل عنصر Intent
معلومات يستخدمها نظام Android لتحديد المكوِّن الذي سيتم بدؤه (مثل اسم المكوِّن الدقيق أو فئة المكوِّن التي يجب أن تتلقى intent)، بالإضافة إلى المعلومات التي يستخدمها المكوِّن الخاص بالمستلم لتنفيذ الإجراء بشكل صحيح (مثل الإجراء المطلوب اتخاذه والبيانات المطلوب اتخاذ إجراء بناءً عليها).
في ما يلي المعلومات الأساسية الواردة في Intent
:
- اسم المكوِّن
- اسم المكوّن الذي سيتم تشغيله.
هذا الإجراء اختياري، ولكنه يُعدّ المعلومات المهمة التي تجعل الintent واضحًا، ما يعني أنّه يجب إرسال الintent إلى مكوّن التطبيق فقط الذي يحدّده اسم المكوّن. في حال عدم إضافة اسم للمكوِّن، يكون الغرض ضمنيًا، ويحدِّد النظام المكوّن الذي يجب أن يتلقّى الغرض بناءً على معلومات الغرض الأخرى (مثل الإجراء والبيانات والفئة كما هو موضّح أدناه). إذا كنت بحاجة إلى بدء أحد المكوّنات المحدّدة في تطبيقك، عليك تحديد اسم المكوّن.
ملاحظة: عند بدء
Service
، حدِّد دائمًا اسم المكوّن. وبخلاف ذلك، لا يمكنك التأكد من الخدمة التي ستستجيب للغرض، ولن يتمكن المستخدم من معرفة الخدمة التي تبدأ.هذا الحقل من
Intent
هو كائنComponentName
، ويمكنك تحديده باستخدام اسم فئة مؤهَّل بالكامل للمكوّن المستهدَف، بما في ذلك اسم حزمة التطبيق، على سبيل المثال،com.example.ExampleActivity
. يمكنك ضبط اسم المكوِّن باستخدامsetComponent()
أوsetClass()
أوsetClassName()
أو باستخدام الدالة الإنشائيةIntent
. - الإجراء
- سلسلة تحدّد الإجراء العام المطلوب تنفيذه (مثل عرض أو اختيار).
في حال نية البث، هذا هو الإجراء الذي تم تنفيذه ويتم الإبلاغ عنه. يحدّد الإجراء بشكل كبير طريقة تنظيم بقية المعلومات المتعلّقة بالنية، لا سيما المعلومات الواردة في البيانات والإضافات.
يمكنك تحديد إجراءاتك الخاصة لاستخدامها من قِبل النوايا داخل تطبيقك (أو لاستخدامها من قِبل التطبيقات الأخرى لاستدعاء المكوّنات في تطبيقك)، ولكنك عادةً ما تحدّد ثوابت الإجراءات التي تحدّدها فئة
Intent
أو فئات إطار العمل الأخرى. في ما يلي بعض الإجراءات الشائعة لبدء نشاط:ACTION_VIEW
- استخدِم هذا الإجراء في نية مع
startActivity()
عندما يكون لديك بعض المعلومات التي يمكن أن يعرضها النشاط للمستخدم، مثل صورة لعرضها في تطبيق معرض صور أو عنوان لاطلاع عليه في تطبيق خرائط. ACTION_SEND
- يُعرف هذا الإذن أيضًا باسم إذن المشاركة، ويجب استخدامه في إذن مع
startActivity()
عندما يكون لديك بعض البيانات التي يمكن للمستخدم مشاركتها من خلال تطبيق آخر، مثل تطبيق بريد إلكتروني أو تطبيق مشاركة على وسائل التواصل الاجتماعي.
اطّلِع على مرجع فئة
Intent
للحصول على المزيد من الثوابت التي تحدّد الإجراءات العامة. يتم تعريف الإجراءات الأخرى في مكان آخر في إطار عمل Android، مثلSettings
للإجراءات التي تفتح شاشات معيّنة في تطبيق "الإعدادات" للنظام.يمكنك تحديد الإجراء لطلب باستخدام
setAction()
أو باستخدام عنصر إنشاءIntent
.إذا حددت إجراءاتك الخاصة، تأكَّد من تضمين اسم حزمة التطبيق كبادئة، كما هو موضّح في المثال التالي:
Kotlin
const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
Java
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
- البيانات
- معرّف الموارد المنتظم (URI) (كائن
Uri
) الذي يشير إلى البيانات المطلوب التصرف بناءً عليها و/أو نوع MIME لتلك البيانات. ويحدّد الإجراء المستهدَف نوع البيانات المقدَّمة بشكل عام. على سبيل المثال، إذا كان الإجراء هوACTION_EDIT
، يجب أن تحتوي البيانات على معرّف الموارد المتّصل (URI) للمستند المطلوب تعديله.عند إنشاء نية، من المهمّ غالبًا تحديد نوع البيانات (نوع MIME) بالإضافة إلى معرّف الموارد المنتظم (URI). على سبيل المثال، النشاط الذي يمكنه عرض الصور قد لا يتمكن من تشغيل ملف صوتي، على الرغم من أنّ تنسيقات معرّفات الموارد المنتظمة قد تكون متشابهة. يساعد تحديد نوع MIME لبياناتك نظام Android في العثور على أفضل مكوّن لتلقّي طلبك. ومع ذلك، يمكن في بعض الأحيان استنتاج نوع MIME من معرّف الموارد المنتظم (URI)، خاصةً عندما تكون البيانات هي معرّف موارد
content:
المنتظم. يشيرcontent:
URI إلى أنّ البيانات متوفّرة على الجهاز ويتحكم فيهاContentProvider
، ما يجعل نوع MIME للبيانات مرئيًا للنظام.لضبط عنوان URI للبيانات فقط، اتصل بالرقم
setData()
. لضبط نوع MIME فقط، يمكنك طلبsetType()
. إذا لزم الأمر، يمكنك ضبط كليهما بشكل صريح باستخدامsetDataAndType()
.تحذير: إذا كنت تريد ضبط كل من معرّف الموارد المنتظم ونوع MIME، لا تستخدِم
setData()
وsetType()
لأنّ كلّ منهما يُلغي قيمة الآخر. استخدِم دائمًاsetDataAndType()
لضبط كلٍّ من عنوان URL ونوع MIME. - الفئة
- سلسلة تحتوي على معلومات إضافية عن نوع المكوّن
الذي من المفترض أن يعالج النية يمكن وضع أي عدد من أوصاف الفئات في قصد، لكن معظم النوايا لا تتطلب فئة.
في ما يلي بعض الفئات الشائعة:
CATEGORY_BROWSABLE
- يسمح النشاط المستهدَف لمتصفّح الويب ببدءه لعرض البيانات التي يشير إليها رابط، مثل صورة أو رسالة إلكترونية.
CATEGORY_LAUNCHER
- النشاط هو النشاط الأولي للمهمة ويتم إدراجه في مشغّل تطبيقات النظام.
اطّلِع على وصف فئة
Intent
للحصول على القائمة الكاملة للفئات.يمكنك تحديد فئة باستخدام
addCategory()
.
تمثّل السمات المذكورة أعلاه (اسم المكوّن والإجراء والبيانات والفئة) الخصائص المحدّدة للنية. من خلال قراءة هذه السمات، يتمكّن نظام Android من تحديد مكوّن التطبيق الذي يجب تشغيله. ومع ذلك، يمكن أن يتضمن intent معلومات إضافية لا تؤثر في كيفية حلها لأحد مكونات التطبيق. يمكن أن يوفّر الغرض أيضًا المعلومات التالية:
- الإضافات
- أزواج المفاتيح والقيم التي تحتوي على معلومات إضافية مطلوبة لإكمال
الإجراء المطلوب
تمامًا كما تستخدم بعض الإجراءات أنواعًا معيّنة من عناوين URL للبيانات، تستخدم بعض الإجراءات أيضًا عناصر إضافية معيّنة.
يمكنك إضافة بيانات إضافية باستخدام طرق
putExtra()
مختلفة، يقبل كلّ منها مَعلمتَين: اسم المفتاح والقيمة. يمكنك أيضًا إنشاء كائنBundle
بجميع البيانات الإضافية، ثم إدراجBundle
فيIntent
باستخدامputExtras()
.على سبيل المثال، عند إنشاء نية لإرسال رسالة إلكترونية باستخدام
ACTION_SEND
، يمكنك تحديد المستلِم إلى باستخدام المفتاحEXTRA_EMAIL
، وتحديد الموضوع باستخدام المفتاحEXTRA_SUBJECT
.تحدّد فئة
Intent
العديد من الثوابتEXTRA_*
لأنواع البيانات الموحدة. إذا كنت بحاجة إلى الإفصاح عن مفاتيح إضافية خاصة بك (للنوايا التي يتلقّاها تطبيقك)، احرص على تضمين اسم حزمة تطبيقك كبادئة، كما هو موضّح في المثال التالي:Kotlin
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
Java
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
تحذير: لا تستخدِم بيانات
Parcelable
أوSerializable
عند إرسال نية تتوقّع أن يتلقّاها تطبيق آخر. إذا حاول تطبيق الوصول إلى البيانات في عنصرBundle
ولكن ليس لديه إذن الوصول إلى الفئة المجزّأة أو المتسلسلة، يُنشئ النظام سوىRuntimeException
. - الأعلام
- يتمّ تحديد العلامات في فئة
Intent
التي تعمل كبيانات وصفية لهدف. قد تُعلِم الإشارات نظام Android بكيفية تشغيل نشاط معيّن (على سبيل المثال، تحديد المهمة التي يجب أن ينتمي إليها ) وكيفية التعامل معه بعد تشغيله (على سبيل المثال، ما إذا كان ينتمي إلى قائمة الأنشطة الأخيرة).لمزيد من المعلومات، يُرجى الاطّلاع على طريقة
setFlags()
.
مثال على نية صريحة
الغرض الصريح هو النوع الذي تستخدمه لتشغيل مكوِّن معيّن من مكوِّنات التطبيق، مثل
نشاط أو خدمة معيَّنة في تطبيقك. ولإنشاء هدف صريح، حدِّد
اسم المكوِّن للعنصر Intent
، وجميع
سمات intent الأخرى اختيارية.
على سبيل المثال، إذا أنشأت خدمة في تطبيقك باسم DownloadService
مصمّمة لتنزيل ملف من الويب، يمكنك تشغيلها باستخدام الرمز البرمجي التالي:
Kotlin
// Executed in an Activity, so 'this' is theContext
// The fileUrl is a string URL, such as "http://www.example.com/image.png" val downloadIntent = Intent(this, DownloadService::class.java).apply { data =Uri.parse
(fileUrl) } startService(downloadIntent)
Java
// Executed in an Activity, so 'this' is theContext
// The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse
(fileUrl)); startService(downloadIntent);
يزوِّد Intent(Context, Class)
المنشئ التطبيق Context
والمكوّن
بكائن Class
. وبناءً على ذلك،
يبدأ هذا القصد صراحةً فئة DownloadService
في التطبيق.
لمزيد من المعلومات عن إنشاء خدمة وبدء تشغيلها، يُرجى الاطّلاع على دليل الخدمات.
مثال على النيّة الضمنية
تحدِّد النية الضمنية إجراءً يمكنه استدعاء أي تطبيق على الجهاز يمكنه تنفيذ الإجراء. يكون استخدام النية الضمنية مفيدًا عندما لا يستطيع تطبيقك تنفيذ الإجراء، ولكن من المحتمل أن تتمكّن تطبيقات أخرى من تنفيذه وتريد من المستخدم اختيار التطبيق الذي يريد استخدامه.
على سبيل المثال، إذا كان لديك محتوى تريد من المستخدم مشاركته مع مستخدمين آخرين،
أنشئ نية
باستخدام الإجراء ACTION_SEND
وأضِف عناصر إضافية تحدّد المحتوى المطلوب مشاركته. عند استدعاء
startActivity()
بهذا الغرض، يمكن للمستخدم
اختيار تطبيق لمشاركة المحتوى من خلاله.
Kotlin
// Create the text message with a string. val sendIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_TEXT, textMessage) type = "text/plain" } // Try to invoke the intent. try { startActivity(sendIntent) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Java
// Create the text message with a string. Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // Try to invoke the intent. try { startActivity(sendIntent); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
عند استدعاء startActivity()
، يفحص النظام
جميع التطبيقات المثبَّتة لتحديد التطبيقات التي يمكنها معالجة هذا النوع من النية (نية
تتضمّن الإجراء ACTION_SEND
وتحمل بيانات "text/plain"
). إذا كان هناك تطبيق واحد فقط يمكنه معالجة الطلب، سيتم فتح هذا التطبيق على الفور وسيتم منحه
الهدف. إذا لم تتمكّن أي تطبيقات أخرى من معالجة ذلك، يمكن لتطبيقك رصد
ActivityNotFoundException
التي تحدث. إذا كانت أنشطة متعددة تقبل النية، يُظهِر النظام مربع حوار مثل المعروض في الشكل 2، ليتمكّن المستخدم من اختيار التطبيق الذي يريد استخدامه.
يمكنك أيضًا الاطّلاع على مزيد من المعلومات حول تشغيل تطبيقات أخرى في الدليل المتعلّق بإرسال المستخدم إلى تطبيق آخر.
فرض أداة اختيار التطبيق
عندما يتوفّر أكثر من تطبيق واحد يستجيب للنوايا الضمنية، يمكن للمستخدم اختيار التطبيق الذي يريد استخدامه وجعله الخيار التلقائي للقيام بال الإجراء. تكون إمكانية تحديد خيار تلقائي مفيدة عند تنفيذ إجراء قد يريد المستخدم من أجله استخدام التطبيق نفسه في كل مرة، على سبيل المثال عند فتح صفحة ويب (غالبًا ما يفضل المستخدمون متصفح ويب واحد فقط).
ومع ذلك، إذا كان بإمكان تطبيقات متعددة الاستجابة لطلب التشغيل وقد يريد المستخدم استخدام
تطبيق مختلف في كل مرة، يجب عرض مربّع حوار اختيار بشكل صريح. يطلب مربّع الحوار من العميل اختيار التطبيق الذي سيتم استخدامه لتنفيذ الإجراء (لا يمكن للعميل اختيار تطبيق تلقائي لتنفيذ الإجراء). على سبيل المثال، عندما ينفِّذ تطبيقك إجراء "المشاركة" باستخدام الإجراء ACTION_SEND
، قد يريد المستخدمون المشاركة باستخدام تطبيق مختلف استنادًا
إلى حالتهم الحالية، لذا عليك استخدام مربّع حوار أداة الاختيار دائمًا، كما هو موضّح في الشكل 2.
لعرض أداة الاختيار، أنشئ Intent
باستخدام createChooser()
ونقلها إلى startActivity()
، كما هو موضّح في المثال التالي.
يعرض هذا المثال مربّع حوار يتضمّن قائمة بالتطبيقات التي تستجيب للهدف الذي تم تمريره إلى طريقة createChooser()
وتستخدم النص المقدَّم كعنوان
مربع الحوار.
Kotlin
val sendIntent = Intent(Intent.ACTION_SEND) ... // Always use string resources for UI text. // This says something like "Share this photo with" val title: String = resources.getString(R.string.chooser_title) // Create intent to show the chooser dialog val chooser: Intent = Intent.createChooser(sendIntent, title) // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(packageManager) != null) { startActivity(chooser) }
Java
Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show the chooser dialog Intent chooser = Intent.createChooser(sendIntent, title); // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
رصد عمليات بدء التطبيقات غير الآمنة
قد يطلق تطبيقك أهدافًا للتنقّل بين المكوّنات داخل تطبيقك، أو لتنفيذ إجراء نيابةً عن تطبيق آخر. لتحسين أمان النظام الأساسي، يوفّر نظام التشغيل Android 12 (المستوى 31 من واجهة برمجة التطبيقات) والإصدارات الأحدث ميزة تصحيح الأخطاء التي تحذرك إذا كان تطبيقك يُجري عملية إطلاق غير آمنة لهدف. على سبيل المثال، قد يُجري تطبيقك عملية إطلاق غير آمنة لهدف مدمج، وهو إجراء يتم تمريره كهدف إضافي في هدف آخر.
إذا نفَّذ تطبيقك كلا الإجراءَين التاليَين، يرصد النظام عملية إطلاق intent غير آمنة، ويحدث انتهاك StrictMode:
- يُفكّ تطبيقك حزمة هدف مُدمَج من البيانات الإضافية لهدف تم إرساله.
- يبدأ تطبيقك على الفور أحد مكونات التطبيق باستخدام هذا الإجراء المتداخل،
مثل تمرير الإجراء إلى
startActivity()
أوstartService()
أوbindService()
.
لمزيد من التفاصيل حول كيفية تحديد هذا الموقف وإجراء تغييرات على تطبيقك، يُرجى قراءة مشاركة المدوّنة حول تداخل طلبات Android على Medium.
التحقّق من عمليات إطلاق المقاصد غير الآمنة
للتحقّق من عمليات إطلاق النوايا غير الآمنة في تطبيقك، يمكنك استدعاء detectUnsafeIntentLaunch()
عند ضبط VmPolicy
، كما هو موضّح في مقتطف الرمز البرمجي التالي. إذا رصد
تطبيقك انتهاكًا لـ StrictMode، ننصحك بإيقاف تنفيذ التطبيق بهدف
حماية المعلومات الحسّاسة المحتملة.
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()) }
Java
protected void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()); }
استخدام النوايا بشكل أكثر مسؤولية
لتقليل احتمالية إطلاق نية غير آمنة وانتهاك StrictMode، اتّبِع أفضل الممارسات التالية.
انسخ الإضافات الأساسية فقط ضمن النوايا، ونفِّذ أي عمليات
تنظيف وتحقّق ضرورية. قد ينسخ تطبيقك البيانات الإضافية من نية إلى
نية أخرى تُستخدَم لتشغيل مكوّن جديد. يحدث ذلك عندما
يستدعي تطبيقك
putExtras(Intent)
أو
putExtras(Bundle)
.
إذا كان تطبيقك ينفّذ إحدى هذه العمليات، يجب نسخ الإضافات التي يتوقعها العنصر المُستلِم فقط. إذا أطلق الغرض الآخر (الذي يتلقى النسخة)
مكونًا لم يتم تصديره، يجب تصحيح
العناصر الإضافية والتحقق منها قبل نسخها إلى الغرض الذي يؤدي
إلى تشغيل المكون.
لا تصدِّر مكوّنات تطبيقك بدون داعٍ. على سبيل المثال، إذا كنت تنوي تشغيل أحد مكونات التطبيق باستخدام هدف مدمج داخلي، اضبط
سمة android:exported
لهذا المكوِّن على false
.
استخدِم PendingIntent
بدلاً من
نية متداخلة. وبهذه الطريقة، عندما يزيل تطبيق آخر PendingIntent
من Intent
الذي يشتمل على، يمكن للتطبيق الآخر تشغيل PendingIntent
باستخدام هوية تطبيقك. تسمح هذه الإعدادات للتطبيق الآخر بتشغيل أي مكوّن بأمان، بما في ذلك أي مكوّن لم يتم تصديره، في تطبيقك.
يوضِّح المخطّط البياني في الشكل 2 كيفية نقل النظام التحكّم من تطبيقك (العميل) إلى تطبيق آخر (خدمة)، ثمّ إعادته إلى تطبيقك:
- ينشئ تطبيقك رسالة Intent تستدعي نشاطًا في تطبيق آخر. ضمن
هذه الرسالة، يمكنك إضافة عنصر
PendingIntent
كعنصر إضافي. يُستخدَم هذا الإجراء المعلّق لتشغيل مكوّن في تطبيقك، ولا يتم تصدير هذا المكوّن. - وعند تلقّي هدف التطبيق، يستخرج التطبيق الآخر عنصر
PendingIntent
المُدمج. - يستدعي التطبيق الآخر الطريقة
send()
على عنصرPendingIntent
. - بعد إعادة عنصر التحكّم إلى تطبيقك، يستدعي النظام النية المعلّقة باستخدام سياق تطبيقك.
الشكل 2. مخطّط بياني للتواصل بين التطبيقات عند استخدام هدف معلق مدمج.
تلقّي نية ضمنية
للإعلان عن الأهداف الضمنية التي يمكن لتطبيقك تلقّيها، حدِّد فلتر هدف واحدًا أو أكثر لكل مكوّن من مكوّنات تطبيقك باستخدام عنصر <intent-filter>
في ملف البيان.
يحدِّد كل فلتر أهداف نوع الأهداف التي يقبلها استنادًا إلى إجراء الهدف
وبياناته وفئتَه. لا يرسل النظام نية ضمنية إلى مكوّن تطبيقك إلا إذا كان
بالإمكان تمرير النيّة من خلال أحد فلاتر النيّات.
ملاحظة: يتم دائمًا إرسال هدف صريح إلى هدفه، بغض النظر عن أي فلاتر أهداف يعلن عنها المكوّن.
يجب أن يعلن مكوّن التطبيق عن فلاتر منفصلة لكل مهمة فريدة يمكنه تنفيذها.
على سبيل المثال، قد يتضمّن نشاط واحد في تطبيق معرض الصور فلترَين: فلتر لعرض صورة، وفلتر آخر لتعديل صورة. عندما يبدأ النشاط، يفحص النظام Intent
ويحدّد كيفية العمل استنادًا إلى المعلومات
الواردة في Intent
(مثل عرض عناصر تحكّم المحرّر).
يتم تحديد كل فلتر أهداف من خلال عنصر <intent-filter>
في ملف بيان التطبيق، ويكون مدمجًا في مكوّن التطبيق المعني (مثل
عنصر <activity>
).
في كل مكوّن تطبيق يتضمّن عنصر <intent-filter>
،
حدِّد قيمة android:exported
صراحةً.
تشير هذه السمة إلى ما إذا كان بإمكان التطبيقات الأخرى الوصول إلى مكوّن التطبيق. في بعض
الحالات، مثل الأنشطة التي تتضمّن فلاتر أهدافها فئة
LAUNCHER
، من المفيد ضبط هذه السمة على true
. وبخلاف ذلك،
من الأفضل ضبط هذه السمة على false
.
تحذير: إذا كان هناك نشاط أو خدمة أو مستقبِل بث في تطبيقك يستخدم فلاتر الأهداف ولم يتم ضبط قيمة android:exported
صراحةً،
لا يمكن تثبيت تطبيقك على جهاز
يعمل بالإصدار 12 من نظام التشغيل Android أو إصدار أحدث.
داخل <intent-filter>
،
يمكنك تحديد نوع النوايا المراد قبولها باستخدام واحد أو أكثر
من هذه العناصر الثلاثة:
<action>
- يُعلن عن قبول إجراء النية في السمة
name
. يجب أن تكون القيمة هي القيمة الحرفية للسلسلة الخاصة بإجراء معيّن، وليس القيمة الثابتة للفئة. <data>
- يُستخدَم لتعريف نوع البيانات المقبولة، باستخدام سمة واحدة أو أكثر تحدد جوانب مختلفة
من معرّف URI للبيانات (
scheme
وhost
وport
path
) ونوع MIME. <category>
- يُعلن عن قبول فئة الغرض في السمة
name
. يجب أن تكون القيمة هي القيمة الحرفية للسلسلة الخاصة بإجراء معيّن، وليس القيمة الثابتة للفئة.ملاحظة: لتلقّي النوايا الضمنية، عليك تضمين فئة
CATEGORY_DEFAULT
في فلتر النوايا. تتعامل الطريقتانstartActivity()
وstartActivityForResult()
مع جميع النوايا كما لو أنّهما أعلنتا عن الفئةCATEGORY_DEFAULT
. إذا لم تحدِّد هذه الفئة في فلتر الأهداف، لن يتم تحويل أي أهداف ضمنية إلى نشاطك.
على سبيل المثال، في ما يلي بيان نشاط يتضمّن فلتر نية لتلقّي نية
ACTION_SEND
عندما يكون نوع البيانات نصًا:
<activity android:name="ShareActivity" android:exported="false"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
يمكنك إنشاء فلتر يتضمّن أكثر من مثيل واحد من
<action>
أو
<data>
أو
<category>
.
وفي حال فعلت ذلك، يجب التأكّد من أنّ المكوّن يمكنه التعامل مع أي تركيبة من تركيبات عناصر الفلتر هذه.
عندما تريد التعامل مع أنواع متعدّدة من النوايا، ولكن في مجموعات محدّدة فقط من نوع الإجراء والبيانات والفئة، عليك إنشاء فلاتر متعددة للنوايا.
يتم اختبار النية الضمنية مقابل فلتر من خلال مقارنة النية بكل من العناصر الثلاثة. لكي يتم إرسال النية إلى المكوّن، يجب أن تجتاز النية جميع الاختبارات الثلاثة. وفي حال تعذّر مطابقة أيٍّ منها، لن يرسل نظام Android النية إلى الادخال. ومع ذلك، بما أنّ المكوّن قد يحتوي على فلاتر متعددة للنوايا، قد يتمكّن أحد الفلاتر من السماح بمرور نية لا تَجتاز أحد فلاتر المكوّن. يمكنك الاطّلاع على مزيد من المعلومات حول كيفية حلّ النظام للنوايا في القسم أدناه المتعلق بحلّ النوايا.
تحذير: لا يُعدّ استخدام فلتر الأهداف طريقة آمنة لمنع التطبيقات الأخرى من بدء
مكوناتك. وعلى الرغم من أن فلاتر الأهداف تقصر استجابة أحد المكونات على أنواع معيّنة فقط من الأهداف الضمنية، إلا أنه من المحتمل أن يبدأ تطبيق آخر مكوّن تطبيقك عن طريق استخدام هدف صريح إذا حدَّد مطوّر البرامج أسماء المكونات.
إذا كان من المهم أن يتمكّن تطبيقك فقط من بدء أحد مكوّناتك،
يجب عدم الإفصاح عن فلاتر الأهداف في البيان. بدلاً من ذلك، اضبط سمة
exported
على "false"
لهذا المكوّن.
وبالمثل، لتجنُّب تشغيل Service
لتطبيق مختلف عن طريق الخطأ، استخدِم دائمًا نية صريحة لبدء خدمتك الخاصة.
ملاحظة:
بالنسبة إلى جميع الأنشطة، يجب الإفصاح عن فلاتر الأهداف في ملف البيان.
ومع ذلك، يمكن تسجيل فلاتر لأجهزة استقبال البث ديناميكيًا من خلال الاتصال
registerReceiver()
. يمكنك بعد ذلك إلغاء تسجيل جهاز الاستقبال لدى unregisterReceiver()
. ويتيح ذلك لتطبيقك إمكانية الاستماع إلى عمليات بث
محددة خلال فترة زمنية محددة فقط أثناء تشغيل التطبيق.
أمثلة على الفلاتر
لتوضيح بعض سلوكيات فلاتر الأهداف، إليك مثال من ملف بيان تطبيق لمشاركة المحتوى على الشبكات الاجتماعية:
<activity android:name="MainActivity" android:exported="true"> <!-- This activity is the main entry, should appear in app launcher --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity" android:exported="false"> <!-- This activity handles "SEND" actions with text data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>
النشاط الأول، MainActivity
، هو نقطة الدخول الرئيسية للتطبيق، وهو النشاط الذي
يفتح عندما يشغّل المستخدم التطبيق في البداية باستخدام رمز مشغّل التطبيقات:
- ويشير الإجراء
ACTION_MAIN
إلى أنّ هذه هي نقطة الدخول الرئيسية، ولا يتوقّع أيّ بيانات عن الغرض منها. - تشير الفئة
CATEGORY_LAUNCHER
إلى أنّه يجب وضع رمز هذا النشاط في مشغّل تطبيقات النظام. إذا لم يحدّد عنصر<activity>
رمزًا باستخدامicon
، سيستخدم النظام الرمز من عنصر<application>
.
يجب إقران هذين العنصرَين معًا لكي يظهر النشاط في مشغّل التطبيقات.
يهدف النشاط الثاني، ShareActivity
، إلى تسهيل مشاركة المحتوى النصي ومحتوى الوسائط. على الرغم من أنّ المستخدمين قد يدخلون إلى هذا النشاط من خلال الانتقال إليه من MainActivity
،
يمكنهم أيضًا الدخول إلى ShareActivity
مباشرةً من تطبيق آخر يُصدر هدفًا ضمنيًا
يتطابق مع أحد فلاتر الأهداف.
ملاحظة: نوع MIME،
application/vnd.google.panorama360+jpg
، هو نوع بيانات خاص يحدّد
الصور البانورامية، والتي يمكنك التعامل معها باستخدام واجهات برمجة تطبيقات Google
panorama.
مطابقة النوايا مع فلاتر أهداف التطبيقات الأخرى
إذا كان تطبيق آخر يستهدف الإصدار Android 13 (المستوى 33 من واجهة برمجة التطبيقات) أو إصدارًا أحدث، يمكنه التعامل مع
هدف تطبيقك فقط إذا تطابق هدفك مع إجراءات وفئات
عنصر <intent-filter>
في ذلك التطبيق الآخر. وإذا لم يعثر النظام على
تطابق، فسيعرض الرمز
ActivityNotFoundException
.
يجب أن يعالج التطبيق المُرسِل
هذا الاستثناء.
وبالمثل، إذا حدَّثت تطبيقك بحيث يستهدف الإصدار 13 من نظام التشغيل Android أو الإصدارات الأحدث، لن يتم إرسال جميع الأهداف الناشئة من تطبيقات خارجية إلى أحد المكونات المُصدَّرة في تطبيقك إلا إذا تطابق هذا الغرض مع الإجراءات وفئات عنصر <intent-filter>
الذي يحدّده تطبيقك. ويحدث هذا السلوك
بغض النظر عن إصدار حزمة SDK المستهدَف للتطبيق المُرسِل.
في الحالات التالية، لا يتم فرض مطابقة الأهداف:
- الأهداف التي يتم إرسالها إلى المكوّنات التي لا تحدّد أي فلاتر أهداف
- الأهداف التي تنشأ من داخل التطبيق نفسه
- النوايا التي تأتي من النظام، أي النوايا التي يتم إرسالها من
"معرّف مستخدم النظام" (uid=1000). تشمل تطبيقات النظام
system_server
والتطبيقات التي تضبطandroid:sharedUserId
علىandroid.uid.system
. - النوايا التي تأتي من الجذر
اطّلِع على مزيد من المعلومات عن مطابقة النية.
استخدام طلب في انتظار المراجعة
عنصر PendingIntent
هو غلاف حول عنصر Intent
. الغرض الأساسي من PendingIntent
هو منح إذن لتطبيق أجنبي
باستخدام Intent
المضمّنة كما لو تم تنفيذها من عملية
تطبيقك الخاصة.
تشمل حالات الاستخدام الرئيسية للنوايا المعلّقة ما يلي:
- الإعلان عن نية التنفيذ عندما ينفِّذ المستخدم إجراءً من خلال الإشعار
(يؤدّي
NotificationManager
في نظام Android إلى تنفيذIntent
). - تحديد نية لتنفيذها عندما ينفِّذ المستخدم إجراءً باستخدام
أداة التطبيق
(ينفِّذ تطبيق الشاشة الرئيسية
Intent
). - الإعلان عن نية تنفيذ في وقت مستقبلي محدّد (ينفّذ
AlarmManager
في نظام AndroidIntent
).
تمامًا كما تم تصميم كل عنصر Intent
ليتم التعامل معه من خلال نوع محدّد
من مكونات التطبيق (إما Activity
أو Service
أو
BroadcastReceiver
)، يجب أيضًا إنشاء PendingIntent
بالطريقة نفسها. عند استخدام نية في انتظار المراجعة، لا يؤدي تطبيقك
إلى تنفيذ النية من خلال طلب مثل startActivity()
. بدلاً من ذلك، عليك تحديد نوع المكوّن المقصود عند إنشاء
PendingIntent
من خلال استدعاء طريقة الإنشاء ذات الصلة:
PendingIntent.getActivity()
لمحاولةIntent
تبدأActivity
PendingIntent.getService()
لمحاولةIntent
لبدءService
PendingIntent.getBroadcast()
لمحاولةIntent
لبدءBroadcastReceiver
ما لم يكن تطبيقك يتلقّى نوايا في انتظار المراجعة من تطبيقات أخرى،
قد تكون الأساليب المذكورة أعلاه لإنشاء PendingIntent
هي PendingIntent
الأساليب الوحيدة التي ستحتاج إليها.
تأخذ كل طريقة التطبيق الحالي Context
وIntent
الذي تريد تغليفه وعلامة واحدة أو أكثر تحدّد كيفية استخدام النية (مثل ما إذا كان يمكن استخدام النية أكثر من مرة).
لمزيد من المعلومات عن استخدام النوايا المعلّقة، اطّلِع على مستندات كل حالة من حالات الاستخدام ذات الصلة، مثل دليلَي واجهة برمجة التطبيقات الإشعارات وتطبيقات المصغّرة.
تحديد قابلية التغيّر
إذا كان تطبيقك يستهدف الإصدار 12 من نظام التشغيل Android أو إصدارًا أحدث، عليك تحديد قابلية التغيّر لكل عناصر PendingIntent
التي ينشئها تطبيقك. لتحديد أنّ
كائن PendingIntent
معيّن قابل للتغيير أو غير قابل للتغيير، استخدِم العلامة
PendingIntent.FLAG_MUTABLE
أو
PendingIntent.FLAG_IMMUTABLE
، على التوالي.
إذا حاول تطبيقك إنشاء عنصر PendingIntent
بدون ضبط أيّ من علامة قابلية التغيّر، سيعرض النظام الرمز
IllegalArgumentException
، وتظهر الرسالة التالية في Logcat:
PACKAGE_NAME: Targeting S+ (version 31 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.
أنشئ طلبات ثابتة في انتظار المراجعة كلما أمكن ذلك.
في معظم الحالات، يجب أن ينشئ تطبيقك عناصر PendingIntent
غير قابلة للتغيير، كما هو موضح في مقتطف الرمز التالي. إذا كان عنصر PendingIntent
غير قابل للتغيير،
لا يمكن للتطبيقات الأخرى تعديل النية لتعديل نتيجة استدعاء
النية.
Kotlin
val pendingIntent = PendingIntent.getActivity(applicationContext, REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE);
ومع ذلك، تتطلّب بعض حالات الاستخدام عناصر PendingIntent
قابلة للتغيير بدلاً من ذلك:
- إتاحة إجراءات الردّ المباشر في
الإشعارات يتطلب الردّ المباشر
تغييرًا في بيانات المقطع في عنصر PendingIntent
المرتبط بالردّ. وعادةً ما تطلب هذا التغيير من خلال تمرير
FILL_IN_CLIP_DATA
كعلامة إلى الأسلوبfillIn()
. - ربط الإشعارات بإطار عمل Android Auto باستخدام مثيلات
CarAppExtender
- وضع المحادثات في فقاعات باستخدام نُسخ
من
PendingIntent
يسمح كائنPendingIntent
قابل للتغيير للنظام بتطبيق العلامات الصحيحة، مثلFLAG_ACTIVITY_MULTIPLE_TASK
وFLAG_ACTIVITY_NEW_DOCUMENT
. - طلب معلومات عن الموقع الجغرافي للجهاز من خلال استدعاء واجهة برمجة التطبيقات
requestLocationUpdates()
أو واجهات برمجة تطبيقات مشابهة يسمح العنصر القابل للتغييرPendingIntent
للنظام بإضافة إضافات الطلبات التي تمثّل أحداث دورة حياة الموقع الجغرافي. وتشمل هذه الأحداث تغييرًا في الموقع الجغرافي وظهور مقدّم خدمة. - جدولة المنبّهات باستخدام
AlarmManager
يسمح عنصرPendingIntent
القابل للتغيير للنظام بإضافةEXTRA_ALARM_COUNT
intent extra. تمثل هذه القيمة الإضافية عدد المرات التي شغّل فيها إنذار متكرر. ومن خلال تضمين هذه المعلومات الإضافية، يمكن للIntent إبلاغ التطبيق بدقة بشأن ما إذا تم تشغيل تنبيه متكرر عدة مرات، مثلاً عندما كان الجهاز في وضع السكون.
إذا كان تطبيقك ينشئ عنصر PendingIntent
قابلاً للتغيير، ننصحك بشدّة
باستخدام نية صريحة وملء الحقل
ComponentName
. بهذه الطريقة، كلما شغّل تطبيق آخر PendingIntent
ونقل التحكّم مرة أخرى إلى تطبيقك، يبدأ المكوّن نفسه في تطبيقك دائمًا.
استخدام النوايا الصريحة ضمن النوايا التي في انتظار المراجعة
لتحديد الطريقة التي يمكن بها للتطبيقات الأخرى استخدام الأهداف المعلّقة في تطبيقك بشكل أفضل، عليك دائمًا تضمين نية في انتظار المراجعة حول نية صريحة. للمساعدة في اتّباع أفضل الممارسات هذه، اتّبِع الخطوات التالية:
- تحقّق من ضبط حقول الإجراء والحزمة والمكوِّن الخاصة بالهدف الأساسي.
-
استخدِم
FLAG_IMMUTABLE
، الذي تمت إضافته في الإصدار 6.0 من نظام التشغيل Android (المستوى 23 من واجهة برمجة التطبيقات)، لإنشاء نوايا في انتظار المراجعة. تمنع هذه العلامة التطبيقات التي تتلقّىPendingIntent
من ملء الخصائص الفارغة. إذا كانminSdkVersion
لتطبيقك هو22
أو إصدارًا أقل، يمكنك توفير الأمان والتوافق معًا باستخدام الرمز التالي:if (Build.VERSION.SDK_INT >= 23) { // Create a PendingIntent using FLAG_IMMUTABLE. } else { // Existing code that creates a PendingIntent. }
دقة النية بالشراء
عندما يتلقّى النظام نية ضمنية لبدء نشاط، يبحث عن أفضل نشاط للنية من خلال مقارنته بفلاتر النيّات استنادًا إلى ثلاثة جوانب:
- تصوير.
- البيانات (معرّف URI ونوع البيانات)
- الفئة.
توضّح الأقسام التالية كيفية مطابقة الأهداف مع المكوّنات المناسبة، وذلك تبعًا لبيان فلتر الأهداف في ملف بيان التطبيق.
اختبار الإجراء
لتحديد إجراءات النوايا المقبولة، يمكن أن يُعلن فلتر الأهداف عن صفر أو أكثر من عناصر
<action>
، كما هو موضّح في المثال التالي:
<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
لاجتياز هذا الفلتر، يجب أن يتطابق الإجراء المحدّد في Intent
مع أحد الإجراءات المدرَجة في الفلتر.
إذا لم يُدرِج الفلتر أي إجراءات، لن يتطابق أي
قصد، وبالتالي لن يجتاز جميع الأغراض الاختبار. ومع ذلك، إذا لم يحدِّد Intent
إجراءً، يجتاز الاختبار ما دام الفلتر
يحتوي على إجراء واحد على الأقل.
اختبار الفئة
لتحديد فئات الأهداف المقبولة، يمكن أن يعلن فلتر الأهداف عن صفر أو أكثر من عناصر
<category>
، كما هو موضّح في المثال التالي:
<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
ولتحقيق نيّة اجتياز اختبار الفئات، يجب أن تتطابق كلّ فئة في Intent
مع فئة معيّنة في الفلتر. ولا يلزم العكس، إذ يمكن أن يُعلن فلتر الأهداف عن
فئات أكثر من تلك المحدّدة فيIntent
، وسيظلIntent
مقبولًا. لذلك، يجتاز الغرض الذي لا يتضمّن أي فئات هذا الاختبار دائمًا،
بغض النظر عن الفئات المُعلَن عنها في الفلتر.
ملاحظة:
يطبّق Android تلقائيًا فئة CATEGORY_DEFAULT
على جميع النوايا الضمنية التي يتم تمريرها إلى startActivity()
وstartActivityForResult()
.
إذا أردت أن يتلقّى نشاطك أغراضًا ضمنية، يجب
أن يتضمّن فئة "android.intent.category.DEFAULT"
في فلاتر الأهداف، كما هو موضّح في مثال <intent-filter>
السابق.
اختبار البيانات
لتحديد بيانات النية المقبولة، يمكن أن يعلن فلتر النية عن صفر أو أكثر من عناصر
<data>
، كما هو موضّح في المثال التالي:
<intent-filter> <data android:mimeType="video/mpeg" android:scheme="http" ... /> <data android:mimeType="audio/mpeg" android:scheme="http" ... /> ... </intent-filter>
يمكن لكل عنصر <data>
تحديد بنية عنوان URL ونوع بيانات (نوع وسائط MIME).
يكون كل جزء من عنوان URI سمة منفصلة: scheme
وhost
وport
وpath
:
<scheme>://<host>:<port>/<path>
يوضّح المثال التالي القيم المحتملة لهذه السمات:
content://com.example.project:200/folder/subfolder/etc
في معرّف الموارد المنتظم هذا، يكون المخطّط هو content
والمضيف هو com.example.project
والمنفذ هو 200
والمسار هو folder/subfolder/etc
.
كلّ من هذه السمات اختيارية في عنصر <data>
،
ولكن هناك تبعيات خطية:
- في حال عدم تحديد مخطط، يتم تجاهل المضيف.
- في حال عدم تحديد مضيف، يتم تجاهل المنفذ.
- في حال عدم تحديد المخطّط والمضيف، يتم تجاهل المسار.
عند مقارنة عنوان URI في الغرض بمواصفات معرف موارد منتظم (URI) في أحد الفلاتر، تتم مقارنته فقط بأجزاء معرّف الموارد المنتظم (URI) المضمّنة في الفلتر. مثلاً:
- إذا كان الفلتر يحدّد مخطّطًا فقط، تتطابق جميع معرّفات URI التي تستخدم هذا المخطّط مع الفلتر.
- إذا حدّد الفلتر مخطّطًا وهيئة ولكن بدون مسار، تمرّ جميع عناوين URL التي تتضمّن المخطّط والهيئة نفسها من الفلتر بغض النظر عن مساراتها.
- إذا حدّد الفلتر مخطّطًا وهيئة ومسارًا، لن تمرّ سوى عناوين URL التي تتضمّن المخطّط والهيئة والمسار نفسه.
ملاحظة: يمكن أن تحتوي مواصفات المسار على علامة النجمة (*) لطلب مطابقة جزئية فقط لاسم المسار.
يقارن اختبار البيانات كلاً من معرّف الموارد المنتظم (URI) ونوع MIME في الطلب مع معرّف موارد منتظم ونوع MIME محدّدَين في الفلتر. في ما يلي القواعد:
- الغرض الذي لا يحتوي على معرّف موارد منتظم (URI) أو نوع MIME: لا يجتاز الاختبار إلا إذا لم يحدِّد الفلتر أي معرّفات موارد منتظمة (URI) أو أنواع MIME.
- لا يجتاز الاختبار إلا إذا كان معرّف الموارد المنتظم (URI) الخاص به يتطابق مع تنسيق معرّف الموارد المنتظم للفلتر ولم يحدّد الفلتر نوع MIME أيضًا.
- لا يجتاز الاختبار سوى النية التي تحتوي على نوع MIME ولكن ليس بها عنوان URL، وذلك فقط إذا كان الفلتر يسرد نوع MIME نفسه ولا يحدّد تنسيق عنوان URL.
- لا يجتاز الإجراء الذي يحتوي على معرّف موارد منتظم ونوع MIME (سواء كان صريحًا أو يمكن الاستدلال عليه من
المعرّف) جزء نوع MIME من الاختبار إلا إذا كان
هذا النوع يتطابق مع نوع مُدرَج في الفلتر. يجتاز الاختبار جزء معرّف الموارد المنتظم (URI)
إما إذا كان معرّف الموارد المنتظم يتطابق مع معرّف موارد منتظم في الفلتر أو إذا كان يحتوي على معرّف موارد منتظم
content:
أوfile:
ولم يحدّد الفلتر معرّف موارد منتظمًا. بعبارة أخرى، يُفترض أنّ المكوّن متوافق مع بياناتcontent:
وfile:
إذا كانت قائمة الفلتر تتضمّن نوع MIME فقط.
ملاحظة: إذا حدّد الغرض معرّف موارد منتظم (URI) أو نوع MIME، سيتعذّر
اختبار البيانات في حال عدم توفّر عناصر <data>
في <intent-filter>
.
تعكس هذه القاعدة الأخيرة (د) التوقّع بأنّه يمكن للمكونات الحصول على بيانات محلية من ملف أو مقدّم محتوى.
وبالتالي، يمكن أن تُدرِج فلاترها نوع بيانات فقط ولا تحتاج إلى تحديد اسم content:
وfile:
بشكل صريح.
يعرض المثال التالي حالة نموذجية يُعلم فيها عنصر <data>
نظام التشغيل Android بأنّ المكوّن يمكنه الحصول على بيانات الصورة من مقدّم محتوى وعرضه:
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
إنّ الفلاتر التي تحديد نوع البيانات ولكن ليس عنوان URL هي على الأرجح الأكثر شيوعًا لأنّ معظم البيانات المتاحة يتم توزيعها من قِبل مقدّمي المحتوى.
من الإعدادات الشائعة الأخرى فلتر يحتوي على مخطّط ونوع بيانات. على سبيل المثال، يُعلم عنصر <data>
الخاص بنظام التشغيل Android بأنّه
يمكن للمكوّن استرداد بيانات الفيديو من الشبكة لتنفيذ الإجراء:
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
مطابقة الأهداف
تتم مطابقة النوايا مع فلاتر النوايا ليس فقط لاكتشاف المكوّن المستهدف
لتفعيله، ولكن أيضًا لاكتشاف معلومات عن مجموعة
المكوّنات على الجهاز. على سبيل المثال، يعبئ تطبيق Home مشغّل التطبيقات
من خلال العثور على جميع الأنشطة التي تتضمّن فلاتر أهداف تحدّد
ACTION_MAIN
الإجراء و
CATEGORY_LAUNCHER
الفئة.
لا تكون المطابقة ناجحة إلا إذا تطابقت الإجراءات والفئات في الهدف مع الفلتر، كما هو موضّح في المستندات الخاصة بالفئة IntentFilter
.
يمكن لتطبيقك استخدام ميزة مطابقة النوايا بطريقة مشابهة لتلك التي يستخدمها تطبيق Home.
يحتوي PackageManager
على مجموعة من query...()
methods التي تعرض جميع المكوّنات التي يمكنها قبول نية معيّنة، وسلسلة مماثلة من طرق resolve...()
التي تحدّد أفضل مكوّن للردّ على نية معيّنة. على سبيل المثال، تعرِض دالة
queryIntentActivities()
قائمة بجميع الأنشطة التي يمكنها تنفيذ
النيّة التي تم تمريرها كوسيطة، وتعرِض دالة queryIntentServices()
قائمة مشابهة بالخدمات.
ولا تؤدي أيّ من الطريقتَين إلى تفعيل المكوّنات، بل تُدرج فقط المكوّنات التي
يمكنها الاستجابة. هناك طريقة مشابهة،
queryBroadcastReceivers()
، لمستقبِلات البث.