Intent
هو كائن مراسلة يمكنك استخدامه لطلب اتخاذ إجراء من مكوّن تطبيق آخر.
على الرغم من أن الأغراض تسهل التواصل بين المكونات بعدة طرق، إلا أن هناك ثلاث
حالات استخدام أساسية:
- بدء نشاط
يمثّل
Activity
شاشة واحدة في أحد التطبيقات. ويمكنك بدء مثيل جديد منActivity
من خلال تمريرIntent
إلىstartActivity()
. تصف السمةIntent
النشاط للبدء ويحمل أي بيانات ضرورية.إذا كنت تريد تلقّي نتيجة من النشاط عند انتهائه، يُرجى الاتصال بـ
startActivityForResult()
. يتلقّى نشاطك النتيجة كعنصرIntent
منفصل في استدعاءonActivityResult()
الخاص بنشاطك. للمزيد من المعلومات، يُرجى الاطّلاع على دليل الأنشطة. - بدء خدمة
Service
هو مكوِّن ينفذ عمليات في الخلفية بدون واجهة مستخدم. باستخدام نظام التشغيل Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك بدء خدمة باستخدامJobScheduler
. لمزيد من المعلومات عن "JobScheduler
"، يمكنك الاطّلاع علىAPI-reference documentation
.بالنسبة إلى الإصدارات الأقدم من Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، يمكنك بدء خدمة باستخدام أساليب الفئة
Service
. يمكنك بدء خدمة لتنفيذ عملية لمرة واحدة (مثل تنزيل ملف) من خلال تمريرIntent
إلىstartService()
. ويصفIntent
الخدمة للبدء وينقل أي بيانات ضرورية.إذا تم تصميم الخدمة باستخدام واجهة خادم عميل، يمكنك الربط بالخدمة من مكوِّن آخر من خلال تمرير
Intent
إلىbindService()
. لمزيد من المعلومات، يُرجى الاطّلاع على دليل الخدمات. - إرسال بث
الإعلان على جميع الأجهزة هو رسالة يمكن لأي تطبيق استقبالها. يقدم النظام عمليات بث متنوعة لأحداث النظام، مثل عند تشغيل النظام أو بدء شحن الجهاز. يمكنك إرسال بث إلى التطبيقات الأخرى من خلال إدخال
Intent
إلىsendBroadcast()
أوsendOrderedBroadcast()
.
يشرح الجزء المتبقي من هذه الصفحة آلية عمل النية وكيفية استخدامها. للحصول على معلومات ذات صلة، يمكنك الاطّلاع على قسمَي التفاعل مع التطبيقات الأخرى ومشاركة المحتوى.
أنواع النية
هناك نوعان من الأغراض:
- تحدد الأغراض الصريحة التطبيق الذي سيلبي الغرض من خلال تقديم اسم حزمة التطبيق المستهدف أو اسم فئة مكون مؤهل بالكامل. ستستخدم عادةً هدفًا صريحًا لبدء مكون في تطبيقك الخاص، لأنك تعرف اسم فئة النشاط أو الخدمة التي تريد البدء بها. على سبيل المثال، يمكنك بدء نشاط جديد داخل تطبيقك استجابةً لإجراءٍ ما يجريه المستخدم، أو بدء خدمة لتنزيل ملف في الخلفية.
- لا تسمي الأهداف الضمنية مكوِّنًا معيّنًا، بل تشير بدلاً من ذلك إلى إجراء عام ينبغي تنفيذه، ما يسمح لمكوِّن من تطبيق آخر بالتعامل مع هذا الإجراء. على سبيل المثال، إذا كنت تريد أن تعرض للمستخدم موقعًا على الخريطة، فيمكنك استخدام هدف ضمني لطلب أن يعرض تطبيق آخر مؤهّل موقعًا محددًا على الخريطة.
يوضّح الشكل 1 كيفية استخدام الغرض عند بدء أحد الأنشطة. عندما يسمي الكائن Intent
مكوِّن نشاط محدّد صراحةً، يبدأ النظام هذا المكوِّن على الفور.

الشكل 1. كيف يتم تقديم هدف ضمني من خلال النظام لبدء نشاط آخر: [1] ينشئ النشاط أ
Intent
مع وصف للإجراء ويمرره إلى startActivity()
. [2] يبحث نظام Android في جميع التطبيقات
عن فلتر أهداف يتطابق مع الهدف. عند العثور على مطابقة، [3] يبدأ النظام نشاط المطابقة (النشاط ب) من خلال استدعاء طريقة onCreate()
وتمرير Intent
.
عند استخدام هدف ضمني، يعثر نظام Android على المكوّن المناسب للبدء من خلال مقارنة محتوى الغرض مع فلاتر النية المحدّدة في ملف البيان للتطبيقات الأخرى على الجهاز. وإذا تطابق الغرض مع فلتر أهداف، يبدأ النظام هذا المكوِّن ويسلّمه
الكائن Intent
. في حال توافق عدة فلاتر أهداف، يعرض
النظام مربّع حوار حتى يتمكّن المستخدم من اختيار التطبيق المطلوب استخدامه.
عامل تصفية الأهداف هو تعبير في ملف بيان التطبيق يحدد نوع الأغراض التي يرغب المكون في تلقيها. على سبيل المثال، من خلال الإعلان عن فلتر أهداف لأحد الأنشطة، فإنك تجعل من الممكن للتطبيقات الأخرى أن تبدأ نشاطك مباشرةً بنوع معين من النية. وبالمثل، إذا لم تُعلِن عن أي فلاتر أهداف لأحد الأنشطة، يمكن عندئذٍ بدئها بهدف صريح فقط.
تحذير: لضمان أمان تطبيقك، عليك دائمًا
استخدام نية صريحة
عند بدء Service
وعدم إدراج
فلاتر الأهداف لخدماتك. يمثل استخدام نية ضمنية لبدء الخدمة خطرًا أمنيًا، لأنك لا تستطيع التأكد من الخدمة التي ستستجيب للقصد، ولا يمكن للمستخدم معرفة الخدمة التي تبدأ. بدءًا من Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، يطرح
النظام استثناءً في حال طلب البيانات bindService()
بنيّة ضمنية.
تعزيز النية
يحمل الكائن Intent
معلومات يستخدمها نظام Android لتحديد
المكوِّن الذي سيتم البدء فيه (مثل اسم المكوِّن أو فئته بالضبط الذي يجب أن يتلقّى الغرض)، بالإضافة إلى المعلومات التي يستخدمها
المكوِّن المستلِم لتنفيذ الإجراء بشكل صحيح (مثل الإجراء المطلوب اتخاذه والبيانات التي يجب اتخاذ إجراء بشأنها).
في ما يلي المعلومات الأساسية التي يتضمّنها Intent
:
- اسم المكوّن
- اسم المكوِّن للبدء.
وهذا إجراء اختياري، ولكنه المعلومة المهمة التي تجعل الغرض فاضحًا، ما يعني أنه يجب ألا يتم إرسال الغرض إلا إلى مكوّن التطبيق المحدّد من خلال اسم المكوِّن. بدون اسم مكوّن، يكون الغرض ضمنيًا ويحدِّد النظام المكوِّن الذي يجب أن يتلقى الغرض استنادًا إلى معلومات النية الأخرى (مثل الإجراء والبيانات والفئة - كما هو موضّح أدناه). إذا كنت بحاجة إلى بدء مكون معين في تطبيقك، يجب عليك تحديد اسم المكون.
ملاحظة: عند بدء
Service
، حدِّد اسم المكوِّن دائمًا. وبخلاف ذلك، لا يمكنك التأكد من الخدمة التي ستستجيب للقصد، ولا يمكن للمستخدم معرفة الخدمة التي تبدأ.ويمثّل هذا الحقل من
Intent
كائنComponentName
، ويمكنك تحديده باستخدام اسم فئة مؤهل بالكامل للمكوِّن المستهدف، بما في ذلك اسم حزمة التطبيق، مثلcom.example.ExampleActivity
. يمكنك ضبط اسم المكوِّن باستخدامsetComponent()
أوsetClass()
أوsetClassName()
أو باستخدام الدالة الإنشائيةIntent
. - الإجراء
- سلسلة تحدّد الإجراء العام المطلوب تنفيذه (مثل view أو pick)
وفي حالة النية من البث، هذا هو الإجراء الذي حدث ويتم الإبلاغ عنه. يحدد الإجراء إلى حد كبير كيفية تنظيم بقية الغرض، وخاصة المعلومات التي تتضمنها البيانات والإضافات.
يمكنك تحديد إجراءاتك الخاصة للاستخدام حسب الأغراض داخل تطبيقك (أو لاستخدامها بواسطة تطبيقات أخرى لاستدعاء مكوّنات في تطبيقك)، ولكنك عادةً ما تُحدِّد ثوابت الإجراءات التي تحدّدها الفئة
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) الخاص به. على سبيل المثال، قد لا يتمكن النشاط الذي يمكنه عرض الصور من تشغيل ملف صوتي، على الرغم من أن تنسيقات معرف الموارد المنتظم (URI) قد تكون متشابهة. يساعد تحديد نوع MIME لبياناتك نظام Android في العثور على أفضل مكوّن لتلقّي الغرض. ومع ذلك، يمكن أحيانًا استنتاج نوع MIME من معرّف الموارد المنتظم (URI)، خاصةً عندما تكون البيانات هي معرّف الموارد المنتظم (URI)
content:
. يشير معرّف الموارد المنتظم (URI)content:
إلى أنّ البيانات متوفّرة على الجهاز ويتم التحكّم فيها من خلالContentProvider
، ما يجعل البيانات من نوع MIME مرئية للنظام.لضبط معرّف الموارد المنتظم (URI) للبيانات فقط، يمكنك طلب الرقم
setData()
. لضبط نوع MIME فقط، يُرجى طلبsetType()
. وإذا لزم الأمر، يمكنك ضبطهما معًا صراحةً باستخدامsetDataAndType()
.تنبيه: إذا كنت تريد ضبط كلّ من معرّف الموارد المنتظم (URI) ونوع MIME، لا تستدعي
setData()
وsetType()
لأنّ كل منهما يُبطل قيمة الآخر. استخدِمsetDataAndType()
دائمًا لضبط كل من نوع URI ونوع MIME. - الفئة
- سلسلة تحتوي على معلومات إضافية حول نوع المكوِّن الذي يجب أن يعالج الغرض. يمكن وضع أي عدد من أوصاف الفئات في غرض، ولكن معظم الأغراض لا تتطلب فئة.
وفي ما يلي بعض الفئات الشائعة:
CATEGORY_BROWSABLE
- يسمح النشاط الهدف ببدء النشاط الهدف من خلال متصفّح ويب لعرض البيانات المُشار إليها من خلال رابط، مثل صورة أو رسالة بريد إلكتروني.
CATEGORY_LAUNCHER
- النشاط هو النشاط الأولي للمهمة، ويتم إدراجه في مشغّل تطبيقات النظام.
راجِع وصف الصف
Intent
للاطّلاع على القائمة الكاملة للفئات.يمكنك تحديد فئة باستخدام
addCategory()
.
تمثل هذه الخصائص المذكورة أعلاه (اسم المكون والإجراء والبيانات والفئة) السمات المحدِّدة للغرض. من خلال قراءة هذه الخصائص، يتمكن نظام Android من تحديد مكون التطبيق الذي يجب أن يبدأه. ومع ذلك، يمكن أن يتضمن الغرض معلومات إضافية لا تؤثر في كيفية التعامل مع أحد مكونات التطبيق. ويمكن أن يوفّر الغرض أيضًا المعلومات التالية:
- العناصر الإضافية
- أزواج المفتاح/القيمة التي تتضمن المعلومات الإضافية المطلوبة لتنفيذ الإجراء المطلوب.
مثلما تستخدم بعض الإجراءات أنواعًا معينة من معرفات الموارد المنتظمة (URI) للبيانات، تستخدم بعض الإجراءات أيضًا عناصر إضافية معينة.
يمكنك إضافة بيانات إضافية باستخدام طرق
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
، وجميع
خصائص الغرض الأخرى اختيارية.
على سبيل المثال، إذا أنشأت خدمة في تطبيقك، باسم 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
وتتضمّن بيانات "نصية أو عادية"). إذا كان هناك تطبيق واحد فقط يمكنه التعامل مع هذه المشكلة، فسيتم فتح التطبيق على الفور ويتم إعطاؤه الهدف. إذا لم تتمكن أي تطبيقات أخرى من معالجة هذه المشكلة، يمكن لتطبيقك رصد
ActivityNotFoundException
الذي يحدث. إذا قبلت أنشطة متعددة الهدف، يعرض
النظام مربع حوار مثل ذلك المعروض في الشكل 2، حتى يتمكن المستخدم من اختيار التطبيق المراد استخدامه.
يتم أيضًا توفير مزيد من المعلومات حول تشغيل تطبيقات أخرى في الدليل حول إرسال المستخدم إلى تطبيق آخر.

الشكل 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); }
رصد عمليات إطلاق النية غير الآمنة
قد يشغِّل تطبيقك عناصر intent للتنقل بين المكوّنات داخل تطبيقك أو لتنفيذ إجراء نيابةً عن تطبيق آخر. لتحسين أمان النظام الأساسي، يوفّر الإصدار Android 12 (المستوى 31 من واجهة برمجة التطبيقات) والإصدارات الأحدث ميزة تصحيح الأخطاء التي تحذّرك إذا كان تطبيقك ينفِّذ إطلاقًا غير آمن لـ intent. على سبيل المثال، قد ينفِّذ تطبيقك عملية إطلاق غير آمنة لهدف متداخل، وهو هدف يتم تمريره كهدف إضافي في هدف آخر.
إذا نفَّذ تطبيقك كلا الإجراءين التاليَين، سيرصد النظام عملية إطلاق نية غير آمنة، ويحدث انتهاك للسياسة StrictMode:
- لا يوفّر تطبيقك غرضًا مدمجًا من العناصر الإضافية لهدف تم تسليمه.
- يبدأ تطبيقك على الفور مكوّن تطبيق باستخدام هذا الغرض المدمج،
مثل تمرير الغرض إلى
startActivity()
،startService()
، أوbindService()
.
للحصول على مزيد من التفاصيل حول كيفية تحديد هذا الموقف وإجراء تغييرات على تطبيقك، يُرجى قراءة مشاركة المدونة حول Android Nesting Intents على Medium.
التحقّق من عمليات إطلاق النية غير الآمنة
للتحقّق من عمليات إطلاق النية غير الآمنة في تطبيقك، يُرجى الاتصال بالرقم
detectUnsafeIntentLaunch()
عند ضبط VmPolicy
، كما هو موضّح في مقتطف الرمز التالي. إذا اكتشف تطبيقك انتهاكًا صارمًا للوضع المقيّد، فقد ترغب في إيقاف تنفيذ التطبيق لحماية المعلومات التي يحتمل أن تكون حساسة.
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 كيفية تمرير النظام للتحكم من تطبيقك (العميل) إلى تطبيق آخر (خدمة)، والعودة إلى تطبيقك:
- ينشئ تطبيقك غرضًا يستدعي نشاطًا في تطبيق آخر. وضمن هذا الغرض، تتم إضافة كائن
PendingIntent
كعنصر إضافي. يستدعي هذا الغرض المعلق مكونًا في تطبيقك؛ ولا يتم تصدير هذا المكون. - بعد تلقّي الغرض من التطبيق، يستخرج التطبيق الآخر عنصر
PendingIntent
المدمج. - يستدعي التطبيق الآخر الإجراء
send()
في الكائنPendingIntent
. - بعد إعادة ضبط عنصر التحكّم إلى تطبيقك، يستدعي النظام النية المعلَّقة باستخدام سياق تطبيقك.
الشكل 2. رسم تخطيطي للاتصال بين التطبيقات عند استخدام غرض مدمج في انتظار المراجعة.
تلقي هدف ضمني
للإعلان عن الأغراض الضمنية التي يمكن أن يتلقّاها تطبيقك، عليك تحديد فلتر أهداف واحد أو أكثر لكل مكوّن من مكوِّنات تطبيقك
باستخدام عنصر <intent-filter>
في ملف البيان.
يحدد كل فلتر أهداف نوع الأغراض التي يقبلها استنادًا إلى إجراء الغرض وبياناته وفئته. لا يرسل النظام غرضًا ضمنيًا إلى مكوّن تطبيقك إلا إذا
كان من الممكن تمرير هذا الغرض من خلال أحد فلاتر الأهداف.
ملاحظة: يتم دائمًا تسليم الغرض الصريح إلى هدفه، بغض النظر عن أي فلاتر أهداف يذكرها المكوِّن.
يجب أن يعلن مكوِّن التطبيق عن فلاتر منفصلة لكل مهمة فريدة يؤدّيها.
على سبيل المثال، قد يحتوي نشاط واحد في تطبيق معرض الصور على فلترَين: فلتر لعرض الصورة، وآخر لتعديل صورة. عند بدء النشاط،
يفحص Intent
ويحدِّد كيفية التصرّف استنادًا إلى المعلومات
الواردة في Intent
(على سبيل المثال، عرض عناصر التحكم في المحرّر أو لا).
يتم تحديد كل فلتر أهداف من خلال عنصر <intent-filter>
في ملف البيان الخاص بالتطبيق، ويكون مدمجًا في المكوِّن المقابل في التطبيق (مثل
عنصر <activity>
).
في كل مكون من مكونات التطبيق التي تشتمل على عنصر <intent-filter>
،
حدِّد قيمة بوضوح لـ
android:exported
.
تحدد هذه السمة ما إذا كان يمكن للتطبيقات الأخرى الوصول إلى مكوِّن التطبيق. في بعض الحالات، مثل الأنشطة التي تتضمّن فلاتر الأهداف فيها الفئة
LAUNCHER
، من المفيد ضبط هذه السمة على true
. بخلاف ذلك، يكون ضبط هذه السمة أكثر أمانًا على false
.
تحذير: إذا كان هناك نشاط أو خدمة أو جهاز استقبال بث في تطبيقك يستخدم فلاتر الأهداف ولم يحدِّد قيمة android:exported
بشكل صريح، لا يمكن تثبيت تطبيقك على جهاز يعمل بنظام التشغيل Android 12 أو إصدار أحدث.
داخل <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
بانوراما.
مطابقة الأهداف مع فلاتر الأهداف للتطبيقات الأخرى
إذا كان تطبيق آخر يستهدف الإصدار 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
في نظام AndroidIntent
). - إعلان هدف يتم تنفيذه عندما ينفِّذ المستخدم إجراءً باستخدام
أداة التطبيق
(ينفِّذ تطبيق الشاشة الرئيسية
Intent
). - إعلان عن تفعيل هدف في وقت لاحق (يعمل
AlarmManager
في نظام Android على تنفيذIntent
)
مثلما تم تصميم كل عنصر Intent
ليتم التعامل معه من خلال نوع محدّد من مكونات التطبيق (إما Activity
أو Service
أو BroadcastReceiver
)، يجب أيضًا إنشاء PendingIntent
بالاعتبار نفسه. عند استخدام هدف في انتظار المراجعة، لا ينفِّذ تطبيقك
الهدف من خلال طلب مثل startActivity()
. بدلاً من ذلك، عليك الإفصاح عن نوع المكوِّن المقصود عند إنشاء
PendingIntent
من خلال طلب طريقة صانع المحتوى المعنيّة:
PendingIntent.getActivity()
لـIntent
التي تبدأActivity
.PendingIntent.getService()
لـIntent
التي تبدأService
.PendingIntent.getBroadcast()
لـIntent
التي تبدأBroadcastReceiver
.
إذا لم يكن تطبيقك يتلقّى أهدافًا معلّقة من تطبيقات أخرى،
قد تكون الطرق المذكورة أعلاه لإنشاء PendingIntent
هي على الأرجح طرق PendingIntent
الوحيدة التي ستحتاج إليها.
تستخدم كل طريقة التطبيق الحالي Context
والسمة Intent
التي تريد تضمينها، بالإضافة إلى علامة واحدة أو أكثر تحدّد كيفية استخدام الغرض (مثل إمكانية استخدام الغرض أكثر من مرة).
للحصول على مزيد من المعلومات عن استخدام الأغراض في انتظار المراجعة، يُرجى الاطّلاع على الوثائق الخاصة بكل حالة من حالات الاستخدام ذات الصلة، مثلاً في دليلَي واجهة برمجة التطبيقات الإشعارات وApp Widgets.
تحديد قابلية التغيّر
إذا كان تطبيقك يستهدف الإصدار 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
الإضافي. تمثل هذه القيمة الإضافية عدد المرات التي تم فيها تشغيل منبه متكرر. ومن خلال تضمين هذا العنصر الإضافي، يمكن أن يرسِل الغرض إلى التطبيق إشعارًا دقيقًا بما إذا كان قد تم تشغيل تنبيه متكرر عدة مرات، مثل الوقت الذي كان فيه الجهاز في وضع السكون.
إذا أنشأ تطبيقك عنصر PendingIntent
قابل للتغيير، ننصحك بشدة باستخدام هدف فاضح وملء ComponentName
. وبهذه الطريقة، عندما يستدعي تطبيق آخر PendingIntent
ويعيد عنصر التحكّم إلى تطبيقك، يبدأ العنصر نفسه في التطبيق دائمًا.
استخدام أغراض صريحة ضمن الأغراض التي في انتظار المراجعة
لتحديد كيفية استخدام التطبيقات الأخرى لأهداف تطبيقك المعلَّقة بشكل أفضل، يجب دائمًا إحاطة هدف في انتظار المراجعة بهدف فاضح. للمساعدة في اتباع أفضل الممارسات هذه، قم بما يلي:
- تأكَّد من ضبط حقول الإجراء والحزمة والمكوّنات الخاصة بالهدف الأساسي.
-
يُرجى استخدام
FLAG_IMMUTABLE
الذي تمت إضافته في Android 6.0 (المستوى 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>
تحديد بنية معرّف الموارد المنتظم (URI) ونوع البيانات (نوع وسائط MIME).
يُعد كل جزء من عنوان URI سمة
منفصلة: scheme
وhost
وport
وpath
:
<scheme>://<host>:<port>/<path>
يعرض المثال التالي القيم المحتملة لهذه السمات:
content://com.example.project:200/folder/subfolder/etc
في عنوان URI هذا، المخطط هو content
، والمضيف هو com.example.project
، والمنفذ 200
، والمسار folder/subfolder/etc
.
كل سمة اختيارية في عنصر <data>
،
ولكن هناك تبعيات خطية:
- في حال عدم تحديد مخطط، يتم تجاهل المضيف.
- في حال عدم تحديد المضيف، يتم تجاهل المنفذ.
- في حال عدم تحديد كل من المخطط والمضيف، يتم تجاهل المسار.
وعندما تتم مقارنة معرّف الموارد المنتظم (URI) في أحد الأغراض بمواصفات عنوان URL في أحد الفلاتر، تتم مقارنتها فقط بأجزاء عنوان URL المضمّنة في الفلتر. مثلاً:
- إذا كان أحد الفلاتر يحدد مخططًا فقط، ستتطابق جميع معرّفات الموارد المنتظمة (URI) التي تضم هذا المخطط مع الفلتر.
- إذا تم تحديد مخطط ومرجع ولكن بدون مسار، تجتاز جميع عناوين URI التي لديها نفس المخطط والمرجع عامل التصفية بغض النظر عن مساراتها.
- إذا تم تحديد مخطط ومرجع ومسار، لن يتم اجتياز الفلتر سوى معرّفات الموارد المنتظمة التي لها نفس المخطط والسلطة والمسار.
ملاحظة: يمكن أن تحتوي مواصفات المسار على علامة نجمية حرف بدل (*) تتطلب مطابقة جزئية فقط لاسم المسار.
يقارن اختبار البيانات كلاً من معرّف الموارد المنتظم (URI) ونوع MIME في الغرض بمعرّف موارد منتظم (URI) ونوع MIME محدّد في الفلتر. وفي ما يلي القواعد:
- ويجتاز الغرض الذي لا يحتوي على معرّف موارد منتظم أو نوع MIME الاختبار إلا إذا لم يحدّد الفلتر أي معرّفات موارد منتظمة أو أنواع MIME.
- يجتاز الغرض الذي يحتوي على معرّف موارد منتظم (URI) ولكن بدون نوع MIME (ليس صريحًا ولا يمكن استنتاجه من معرّف الموارد المنتظم (URI)) الاختبار إلا إذا كان معرّف الموارد المنتظم (URI) الخاص به يطابق تنسيق URI للفلتر وكان الفلتر لا يحدد أيضًا نوع MIME.
- يجتاز الغرض الذي يحتوي على نوع MIME وليس معرّف موارد منتظم (URI) الاختبار فقط إذا كان الفلتر يدرج نوع MIME نفسه ولم يحدِّد تنسيق معرّف الموارد المنتظم (URI).
- يجتاز الغرض الذي يحتوي على كلٍ من معرّف الموارد المنتظم (URI) ونوع MIME (سواء كان فاضحًا أو قابلاً للاستنتاج من معرّف الموارد المنتظم (URI)) جزء نوع MIME من الاختبار إلا إذا كان هذا النوع مطابقًا لنوع مدرَج في الفلتر. يجتاز قسم عنوان URI في الاختبار إما إذا كان معرّف الموارد المنتظم (URI) الخاص به يتطابق مع معرّف موارد منتظم (URI) في الفلتر أو إذا كان يحتوي على معرّف موارد منتظم (URI)
content:
أوfile:
ولم يحدّد الفلتر معرّف موارد منتظم (URI). بمعنى آخر، يُفترض أن يتوافق المكوِّن مع بياناتcontent:
وfile:
إذا كان فلترته يسرد نوع MIME فقط.
ملاحظة: إذا تم تحديد نوع معرّف الموارد المنتظم (URI) أو نوع MIME، سيتعذّر اختبار البيانات
في حال عدم توفُّر عناصر <data>
في <intent-filter>
.
تعكس هذه القاعدة الأخيرة (د)، التوقع بأن
المكونات يمكنها الحصول على البيانات المحلية من موفر ملف أو محتوى.
وبالتالي، يمكن للفلاتر أن تدرج نوع بيانات فقط بدون الحاجة إلى تسمية المخطط content:
وfile:
بشكل صريح.
يعرض المثال التالي حالة نموذجية يخبر فيها العنصر <data>
نظام التشغيل Android بأنّ المكوِّن يمكنه الحصول على بيانات الصورة من موفّر المحتوى وعرضها:
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
الفلاتر التي تحدّد نوع بيانات وليس معرّف موارد منتظم (URI) هي الأكثر شيوعًا على الأرجح، لأنّ معظم البيانات المتوفّرة يوزّعها موفّرو المحتوى.
هناك تكوين شائع آخر وهو عامل تصفية يحتوي على مخطط ونوع بيانات. على سبيل المثال، يحدد عنصر <data>
، مثل العنصر التالي Android، أنّ المكوِّن يمكنه استرداد بيانات الفيديو من الشبكة لتنفيذ الإجراء:
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
مطابقة النية
تتم مطابقة الأهداف مع فلاتر الأهداف ليس فقط لاكتشاف مكوّن مستهدَف لتفعيله، ولكن أيضًا لاكتشاف شيء عن مجموعة المكوّنات على الجهاز. على سبيل المثال، يملأ تطبيق Home مشغّل التطبيقات من خلال
العثور على جميع الأنشطة التي تحتوي على فلاتر أهداف والتي تحدِّد
إجراء ACTION_MAIN
وفئة
CATEGORY_LAUNCHER
.
لا تكون المطابقة ناجحة إلا إذا تطابقت الإجراءات والفئات الواردة في Intent
على الفلتر، كما هو موضّح في مستندات
فئة IntentFilter
.
ويمكن أن يستخدم تطبيقك مطابقة الأهداف بطريقة تشبه ما يفعله تطبيق Home.
يحتوي PackageManager
على مجموعة من طُرق query...()
التي تعرض جميع المكوّنات التي يمكنها قبول هدف معيّن وسلسلة مشابهة من طُرق resolve...()
التي تحدّد أفضل مكوّن للاستجابة لهدف. على سبيل المثال، تعرض دالة queryIntentActivities()
قائمة بجميع الأنشطة التي يمكن أن تؤدي إلى تنفيذ الغرض الذي تم تمريره كوسيطة، وتعرض queryIntentServices()
قائمة مشابهة من الخدمات.
لا تؤدي أي من الطريقتين إلى تنشيط المكونات، وإنما تسرد فقط العناصر التي
يمكنها الاستجابة. هناك طريقة مشابهة،
وهي queryBroadcastReceivers()
، لأجهزة استقبال البث.