فلاتر الأهداف والنية

Intent هو كائن مراسلة يمكنك استخدامه لطلب إجراء من مكوِّن تطبيق آخر. على الرغم من أن الأهداف تسهل التواصل بين المكونات بعدة طرق، إلا أن هناك ثلاث حالات استخدام أساسية:

  • بدء نشاط

    تمثل Activity شاشة واحدة في تطبيق ما. يمكنك بدء نسخة افتراضية جديدة من Activity من خلال تمرير Intent إلى startActivity(). تصف السمة Intent النشاط للبدء ويحمل أي بيانات ضرورية.

    إذا أردت تلقّي نتيجة من النشاط عند الانتهاء، يمكنك طلب startActivityForResult(). يتلقّى نشاطك النتيجة على شكل كائن Intent منفصل في استدعاء onActivityResult() لنشاطك. لمزيد من المعلومات، اطّلِع على دليل الأنشطة.

  • بدء خدمة

    Service هو مكوِّن ينفِّذ العمليات في الخلفية بدون واجهة مستخدم. في الإصدار 5.0 من نظام التشغيل Android (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك بدء خدمة باستخدام JobScheduler. لمزيد من المعلومات حول JobScheduler، يمكنك الاطّلاع على API-reference documentation الخاصة به.

    أمّا في الإصدارات الأقدم من Android 5.0 (المستوى 21 لواجهة برمجة التطبيقات)، يمكنك بدء خدمة باستخدام طرق من الفئة Service. يمكنك بدء خدمة لإجراء عملية لمرة واحدة (مثل تنزيل ملف) من خلال تمرير Intent إلى startService(). تصف Intent الخدمة لبدء العمل وتنقل أي بيانات ضرورية.

    إذا تم تصميم الخدمة باستخدام واجهة خادم عميل، يمكنك الربط بالخدمة من مكوِّن آخر عن طريق تمرير Intent إلى bindService(). لمزيد من المعلومات، يُرجى الاطّلاع على دليل الخدمات.

  • إرسال بث

    البث هو رسالة يمكن أن يتلقاها أي تطبيق. يعرض النظام عمليات بث متنوعة لأحداث النظام، على سبيل المثال عند تشغيل النظام أو بدء شحن الجهاز. يمكنك إرسال بث إلى تطبيقات أخرى من خلال ضبط Intent إلى sendBroadcast() أو sendOrderedBroadcast().

توضّح هذه الصفحة آلية عمل الأهداف وكيفية استخدامها. للحصول على معلومات ذات صلة، راجِع التفاعل مع التطبيقات الأخرى ومشاركة المحتوى.

أنواع الأهداف

هناك نوعان من الأهداف:

  • الأهداف الصريحة تحدد مكوّن التطبيق الذي سيفي بالغرض، من خلال تحديد ComponentName كامل. ستستخدم عادةً هدفًا صريحًا لبدء مكون في تطبيقك الخاص، لأنك تعرف اسم فئة النشاط أو الخدمة التي تريد تشغيلها. على سبيل المثال، يمكنك بدء نشاط جديد داخل تطبيقك استجابةً لإجراء المستخدم، أو بدء خدمة لتنزيل ملف في الخلفية.
  • لا تسمّي الأهداف الضمنية مكوّنًا معيّنًا، بل تعلن بدلاً من ذلك عن إجراء عام يجب تنفيذه، ما يسمح لمكون من تطبيق آخر بمعالجة هذا الإجراء. فمثلاً، إذا كنت تريد أن تعرض للمستخدم موقعًا جغرافيًا على خريطة، يمكنك استخدام نية ضمنية لطلب عرض موقع جغرافي محدّد على الخريطة من خلال تطبيق آخر مؤهَّل.

يوضح الشكل 1 كيفية استخدام هدف عند بدء نشاط. عندما يسمي الكائن Intent مكون نشاط معيّن بشكل صريح، يبدأ النظام هذا المكوّن على الفور.

الشكل 1. كيفية إرسال هدف ضمني من خلال النظام لبدء نشاط آخر: [1] يُنشئ النشاط "أ" Intent وصفًا للإجراء ويمرره إلى startActivity(). [2] يبحث نظام Android في جميع التطبيقات عن فلتر أهداف يتطابق مع الهدف. عند العثور على مطابقة، [3] يبدأ النظام نشاط المطابقة (النشاط ب) من خلال استدعاء طريقة onCreate() وتمرير Intent.

عند استخدام هدف ضمني، يعثر نظام Android على المكوّن المناسب للبدء من خلال مقارنة محتوى الغرض مع فلاتر الأهداف التي تم تعريفها في ملف البيان الخاص بالتطبيقات الأخرى على الجهاز. إذا تطابق الغرض مع فلتر أهداف، يبدأ النظام هذا المكوّن ويسلمه الكائن Intent. إذا كانت فلاتر الأهداف المتعددة متوافقة، سيعرض النظام مربع حوار حتى يتمكن المستخدم من اختيار التطبيق المطلوب استخدامه.

فلتر الأهداف هو تعبير في ملف بيان التطبيق يحدد نوع الأهداف التي يرغب المكوِّن في تلقيها. على سبيل المثال، عند تعريفك بعامل تصفية الأهداف لأحد الأنشطة، فإنك تسمح للتطبيقات الأخرى ببدء نشاطك مباشرةً بنيّة معيّنة. وبالمثل، إذا لم تُفصح عن أي فلاتر أهداف لنشاط ما، فلا يمكن بدؤه إلا بنيّة صريحة.

تنبيه: لضمان أمان تطبيقك، يُرجى دائمًا استخدام نية صريحة عند بدء استخدام Service وعدم تعريف فلاتر الأهداف لخدماتك. ويشكّل استخدام نية ضمنية لبدء خدمة خطرًا أمنيًا لعدم القدرة على التأكُّد من استجابة الخدمة لهدف الخدمة، ولا يستطيع المستخدم معرفة الخدمة التي سيتم تشغيلها. بدءًا من Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، يعرض النظام استثناءً في حال استدعاء الدالة bindService() لغرض ضمني.

بناء هدف

يحتوي عنصر Intent على معلومات يستخدمها نظام Android لتحديد المكوِّن الذي سيتم بدؤه (مثل اسم المكوِّن الدقيق أو فئة المكوِّن التي يجب أن تتلقى intent)، بالإضافة إلى المعلومات التي يستخدمها المكوِّن الخاص بالمستلم لتنفيذ الإجراء بشكل صحيح (مثل الإجراء المطلوب اتخاذه والبيانات التي سيتم اتخاذ إجراء بناءً عليها).

المعلومات الأساسية التي يتضمّنها Intent هي ما يلي:

اسم المكوِّن
اسم المكوِّن المطلوب البدء.

هذه الخطوة اختيارية، ولكنها المعلومة المهمة التي تجعل الغرض صريحًا، ما يعني أنّه يجب تسليم الغرض إلى مكوّن التطبيق الذي يتم تحديده من خلال اسم المكوِّن فقط. في حال عدم إضافة اسم للمكوِّن، يكون الغرض ضمنيًا، ويحدِّد النظام المكوّن الذي يجب أن يتلقّى الغرض بناءً على معلومات الغرض الأخرى (مثل الإجراء والبيانات والفئة كما هو موضّح أدناه). إذا كنت بحاجة إلى بدء مكون معين في تطبيقك، فيجب تحديد اسم المكون.

ملاحظة: عند بدء Service، حدِّد دائمًا اسم المكوِّن. وبخلاف ذلك، لا يمكنك التأكد من الخدمة التي ستستجيب للغرض، ولن يتمكن المستخدم من معرفة الخدمة التي تبدأ.

يمثّل حقل Intent هذا كائنًا ComponentName يمكنك تحديده باستخدام اسم فئة مؤهّل بالكامل للمكون الهدف، بما في ذلك اسم حزمة التطبيق، مثل com.example.ExampleActivity. يمكنك ضبط اسم المكوِّن باستخدام setComponent() أو setClass() أو setClassName() أو باستخدام الدالة الإنشائية Intent.

الإجراء
سلسلة تحدد الإجراء العام المطلوب تنفيذه (مثل عرض أو اختيار).

في ما يتعلق بالغرض من البث، هذا هو الإجراء الذي تم إجراؤه والذي يتم الإبلاغ عنه. يحدد الإجراء إلى حد كبير كيفية هيكلة باقي الغرض - لا سيما المعلومات الموجودة في البيانات والإضافات.

يمكنك تحديد إجراءاتك الخاصة لتستخدمها الأهداف داخل تطبيقك (أو لاستخدامها بواسطة تطبيقات أخرى لاستدعاء مكوّنات في تطبيقك)، ولكن عادةً ما تُحدِّد ثوابت الإجراء التي تحدّدها فئة Intent أو فئات أُطر عمل أخرى. فيما يلي بعض الإجراءات الشائعة لبدء نشاط ما:

ACTION_VIEW
استخدِم هذا الإجراء في intent في 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.

الفئة
سلسلة تحتوي على معلومات إضافية عن نوع المكوِّن الذي يجب أن يتعامل مع intent. يمكن وضع أي عدد من أوصاف الفئات في قصد، لكن معظم النوايا لا تتطلب فئة. وفي ما يلي بعض الفئات الشائعة:
CATEGORY_BROWSABLE
يسمح متصفّح الويب ببدء النشاط المستهدَف لعرض البيانات المُشار إليها من خلال رابط، مثل صورة أو رسالة إلكترونية.
CATEGORY_LAUNCHER
النشاط هو النشاط الأولي لمهمة ما ويتم إدراجه في مشغّل تطبيقات النظام.

واطّلِع على وصف الفئة Intent للاطّلاع على القائمة الكاملة للفئات.

يمكنك تحديد فئة باستخدام addCategory().

تمثل هذه الخصائص المدرجة أعلاه (اسم المكون والإجراء والبيانات والفئة) الخصائص المحددة للغرض. من خلال قراءة هذه الخصائص، يمكن لنظام Android تحديد مكون التطبيق الذي يجب أن يبدأ. ومع ذلك، يمكن أن يتضمن intent معلومات إضافية لا تؤثر في كيفية حلها لأحد مكونات التطبيق. يمكن أن يقدم الغرض أيضًا المعلومات التالية:

الإضافات
أزواج المفتاح/القيمة التي تتضمّن المعلومات الإضافية المطلوبة لتنفيذ الإجراء المطلوب. مثلما تستخدم بعض الإجراءات أنواعًا معينة من معرفات الموارد المنتظمة (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، وجميع سمات intent الأخرى اختيارية.

على سبيل المثال، إذا أنشأت خدمة في تطبيقك باسم DownloadService ومصمّمة لتنزيل ملف من الويب، يمكنك تشغيلها بالرمز التالي:

Kotlin

// Executed in an Activity, so 'this' is the Context
// 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 the Context
// 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);
}

رصد عمليات الإطلاق غير الآمنة حسب نية العميل

قد يطلق تطبيقك أهدافًا للتنقل بين المكوّنات داخل تطبيقك أو لتنفيذ إجراء نيابةً عن تطبيق آخر. ولتحسين مستوى أمان النظام الأساسي، يوفّر Android 12 (المستوى 31 من واجهة برمجة التطبيقات) والإصدارات الأحدث ميزة تصحيح الأخطاء التي تحذّرك في حال تنفيذ تطبيقك لهدف غير آمن. على سبيل المثال، قد يُجري تطبيقك عملية إطلاق غير آمنة لهدف مدمج، وهو إجراء يتم تمريره كهدف إضافي في هدف آخر.

إذا نفَّذ تطبيقك الإجراءَين التاليَين، يرصد النظام إطلاق نية غير آمنة ويحدث انتهاك شديد للوضع:

  1. يفصل تطبيقك عن الغرض المدمج من العناصر الإضافية لهدف تم إرساله.
  2. يبدأ تطبيقك على الفور مكوّن تطبيق باستخدام هذا الغرض المدمج، مثل تمرير intent إلى startActivity() أو startService() أو bindService().

لمزيد من التفاصيل حول كيفية تحديد هذا الموقف وإجراء تغييرات على تطبيقك، اقرأ مشاركة المدونة حول أهداف Android Nesting على Medium.

التحقّق من عمليات الإطلاق غير الآمنة حسب نية العميل

للتحقّق من عمليات تشغيل intent غير الآمنة في تطبيقك، يمكنك استدعاء 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 كيفية تمرير النظام للتحكم من تطبيقك (العميل) إلى تطبيق (خدمة) آخر، والعودة إلى تطبيقك:

  1. ينشئ تطبيقك هدفًا يستدعي نشاطًا في تطبيق آخر. وفي إطار ذلك الغرض، يمكنك إضافة عنصر PendingIntent كعنصر إضافي. يستدعي هذا الغرض المعلق مكونًا في تطبيقك؛ ولا يتم تصدير هذا المكون.
  2. وعند تلقّي هدف التطبيق، يستخرج التطبيق الآخر عنصر PendingIntent المُدمج.
  3. يستدعي التطبيق الآخر الطريقة send() على الكائن PendingIntent.
  4. بعد إعادة عنصر التحكّم إلى تطبيقك، يستدعي النظام النية المعلّقة باستخدام سياق تطبيقك.

الشكل 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 بانوراما.

مطابقة الأهداف بفلاتر الأهداف لتطبيقات أخرى

إذا كان تطبيق آخر يستهدف Android 13 (المستوى 33 من واجهة برمجة التطبيقات) أو إصدارًا أحدث، يمكنه التعامل مع هدف تطبيقك فقط إذا تطابق هدفك مع إجراءات وفئات عنصر <intent-filter> في ذلك التطبيق الآخر. وإذا لم يعثر النظام على تطابق، فسيعرض الرمز ActivityNotFoundException. ويجب أن يتعامل تطبيق الإرسال مع هذا الاستثناء.

وبالمثل، إذا حدَّثت تطبيقك بحيث يستهدف الإصدار 13 من نظام التشغيل Android أو الإصدارات الأحدث، لن يتم إرسال جميع الأهداف الناشئة من تطبيقات خارجية إلى أحد المكونات المُصدَّرة في تطبيقك إلا إذا تطابق هذا الغرض مع إجراءات وفئات عنصر <intent-filter> الذي يحدّده تطبيقك. ويحدث هذا السلوك بغض النظر عن إصدار حزمة تطوير البرامج (SDK) المستهدَف للتطبيق الذي يتم منه إرسال الرسائل.

في الحالات التالية، لا يتم فرض مطابقة الأهداف:

  • الأهداف التي يتم إرسالها إلى المكوّنات التي لا تشير إلى أي فلاتر أهداف.
  • الأهداف التي تنشأ من داخل التطبيق نفسه
  • هي عبارة عن أهداف تنشأ من النظام، أي إنّها أغراض يتم إرسالها من "system UID" (uid=1000). تشمل تطبيقات النظام system_server والتطبيقات التي تضبط android:sharedUserId على android.uid.system.
  • النوايا التي تنشأ من الجذر.

اطّلِع على مزيد من المعلومات عن مطابقة الرغبة في الشراء.

استخدام هدف في انتظار المراجعة

الكائن PendingIntent هو التفاف حول كائن Intent. الغرض الأساسي من PendingIntent هو منح الإذن لتطبيق أجنبي باستخدام Intent المضمّن كما لو تم تنفيذه من العملية الخاصة بالتطبيق.

تشمل حالات الاستخدام الرئيسية لهدف في انتظار المراجعة ما يلي:

  • الإعلان عن نية التنفيذ عندما ينفِّذ المستخدم إجراءً من خلال الإشعار (يؤدّي NotificationManager في نظام Android إلى تنفيذ Intent).
  • الإعلان عن نية التنفيذ عندما ينفِّذ المستخدم إجراءً باستخدام أداة التطبيق (ينفِّذ تطبيق "الشاشة الرئيسية" Intent).
  • الإعلان عن نية التنفيذ في وقت محدّد في المستقبل (ينفّذ AlarmManager في نظام Android العملية Intent).

وتمامًا كما يتم تصميم كل عنصر Intent ليتعامل معه نوع محدّد من مكونات التطبيق (إما Activity أو Service أو BroadcastReceiver)، كذلك يجب إنشاء PendingIntent مع مراعاة التفكير نفسه. عند استخدام هدف في انتظار المراجعة، لا ينفِّذ تطبيقك الغرض من خلال طلب مثل startActivity(). بدلاً من ذلك، يجب تعريف نوع المكوِّن المقصود عند إنشاء PendingIntent من خلال استدعاء طريقة المنشئ المعنية:

ما لم يكن تطبيقك يتلقّى عناصر intent في انتظار المراجعة من تطبيقات أخرى، من المحتمل أن تكون الطرق المذكورة أعلاه لإنشاء PendingIntent هي PendingIntent طرق الاستخدام الوحيدة التي ستحتاج إلى استخدامها.

تأخذ كل طريقة التطبيق الحالي Context وIntent الذي تريد التفافه وعلامة واحدة أو أكثر من العلامات التي تحدد كيفية استخدام الغرض (مثلاً، إمكانية استخدام intent أكثر من مرة).

لمزيد من المعلومات عن استخدام عناصر intent في انتظار المراجعة، يمكنك الاطّلاع على المستندات المرتبطة بكل حالة من حالات الاستخدام المعنيّة، كما هو الحال في دليلَي واجهة برمجة التطبيقات Notifications (الإشعارات) و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 ويعيد عنصر التحكم إلى تطبيقك، يبدأ دائمًا العنصر نفسه في تطبيقك.

استخدام أهداف صريحة ضمن الأهداف التي تنتظر المراجعة

لتحديد الطريقة التي يمكن بها للتطبيقات الأخرى استخدام الأهداف المعلّقة في تطبيقك بشكل أفضل، عليك دائمًا تضمين نية في انتظار المراجعة حول نيّة صريحة. للمساعدة في اتّباع أفضل الممارسات هذه، اتّبِع الخطوات التالية:

  1. تحقّق من ضبط حقول الإجراء والحزمة والمكوِّن الخاصة بالهدف الأساسي.
  2. يمكنك استخدام 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

في معرّف الموارد المنتظم هذا، المخطط هو content، والمضيف هو com.example.project، والمنفذ هو 200، والمسار هو folder/subfolder/etc.

كل سمة من هذه السمات اختيارية في العنصر <data>، ولكن هناك تبعيات خطية:

  • في حال عدم تحديد مخطط، يتم تجاهل المضيف.
  • في حال عدم تحديد مضيف، سيتم تجاهل المنفذ.
  • في حال عدم تحديد كل من المخطط والمضيف، سيتم تجاهل المسار.

عند مقارنة عنوان URI في الغرض بمواصفات معرف موارد منتظم (URI) في أحد الفلاتر، تتم مقارنته فقط بأجزاء معرّف الموارد المنتظم (URI) المضمّنة في الفلتر. على سبيل المثال:

  • إذا حدّد أحد الفلاتر مخططًا فقط، ستتطابق جميع معرّفات الموارد المنتظمة (URI) التي تتضمّن هذا المخطط مع الفلتر.
  • إذا حدّد أحد الفلاتر مخططًا ومرجعًا ولكن بدون مسار، ستجتاز جميع معرّفات الموارد المنتظمة (URI) التي لها المخطّط والسلطة نفسهما الفلتر بغضّ النظر عن مساراتها.
  • إذا حدّد أحد الفلاتر مخططًا ومرجعًا ومسارًا، ستجتاز معرّفات الموارد المنتظمة (URI) التي تتضمّن نفس المخطّط والسلطة والمسار فقط عامل التصفية.

ملاحظة: يمكن أن يحتوي مواصفات المسار على علامة نجمية حرف بدل (*) لطلب تطابق جزئي فقط لاسم المسار.

يقارن اختبار البيانات كلاً من معرّف الموارد المنتظم (URI) ونوع MIME في الغرض مع معرّف الموارد المنتظم (URI) ونوع MIME المحدّد في الفلتر. القواعد على النحو التالي:

  1. الغرض الذي لا يحتوي على معرّف موارد منتظم (URI) أو نوع MIME: لا يجتاز الاختبار إلا إذا لم يحدِّد الفلتر أي معرّفات موارد منتظمة (URI) أو أنواع MIME.
  2. يجتاز الغرض الذي يتضمّن معرّف موارد منتظم (URI) بدون نوع MIME (ليس صريحًا ولا يمكن استنتاجه من عنوان URI) الاختبار إلا إذا كان معرّف الموارد المنتظم (URI) الخاص به يطابق تنسيق معرّف الموارد المنتظم (URI) للفلتر ولا يحدِّد الفلتر أيضًا نوع MIME.
  3. يجتاز الغرض الذي يحتوي على نوع MIME وليس معرّف موارد منتظم (URI) الاختبار فقط إذا كان الفلتر يدرج نوع MIME نفسه ولا يحدّد تنسيق معرّف موارد منتظم (URI).
  4. ويجتاز الغرض الذي يشتمل على كل من معرّف الموارد المنتظم (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. لا تكون المطابقة ناجحة إلا إذا تطابقت الإجراءات والفئات في الهدف مع الفلتر، كما هو موضّح في المستندات الخاصة بالفئة IntentFilter.

يمكن أن يستخدم تطبيقك ميزة "مطابقة الأهداف" بطريقة مشابهة لتلك التي يستخدمها تطبيق Home. يتضمّن PackageManager مجموعة من طرق query...() التي تعرض جميع المكوّنات التي يمكنها قبول هدف معيّن وسلسلة مشابهة من طرق resolve...() التي تحدّد أفضل مكوّن للاستجابة إلى هدف معيّن. على سبيل المثال، تعرض الدالة queryIntentActivities() قائمة بجميع الأنشطة التي يمكنها تنفيذ الغرض الذي تم تمريره كوسيطة، ويعرض queryIntentServices() قائمة مشابهة من الخدمات. لا تعمل أي من الطريقتين على تنشيط المكونات؛ بل تقوم فقط بإدراج العناصر التي يمكنها الاستجابة. تتوفر طريقة مماثلة، queryBroadcastReceivers()، لأجهزة استقبال البث.