מסנני Intent ומסנני Intent

Intent הוא אובייקט שליחת הודעות שאפשר להשתמש בו כדי לבקש פעולה מרכיב אחר באפליקציה. אובייקטים מסוג Intent מאפשרים תקשורת בין רכיבים בכמה דרכים, אבל יש שלושה תרחישי שימוש בסיסיים:

  • התחלת פעילות

    Activity מייצג מסך יחיד באפליקציה. אפשר להתחיל מופע חדש של Activity על ידי העברת Intent אל startActivity(). השדה Intent מתאר את הפעילות שרוצים להתחיל ונושא את הנתונים הנדרשים.

    אם רוצים לקבל תוצאה מהפעילות בסיום, צריך להתקשר למספר startActivityForResult(). הפעילות מקבלת את התוצאה כאובייקט Intent נפרד בקריאה החוזרת onActivityResult() של הפעילות. מידע נוסף זמין במדריך פעילויות.

  • הפעלת שירות

    Service הוא רכיב שמבצע פעולות ברקע בלי ממשק משתמש. ב-Android מגרסה 5.0 (רמת API‏ 21) ואילך, אפשר להפעיל שירות באמצעות JobScheduler. למידע נוסף על JobScheduler, אפשר לעיין בAPI-reference documentation שלו.

    בגרסאות ישנות יותר מ-Android 5.0 (רמת API‏ 21), אפשר להפעיל שירות באמצעות שיטות של הכיתה Service. כדי להפעיל שירות לביצוע פעולה חד-פעמית (למשל, הורדת קובץ), מעבירים Intent אל startService(). השדה Intent מתאר את השירות שרוצים להפעיל ומכיל את הנתונים הנדרשים.

    אם השירות תוכנן עם ממשק לקוח-שרת, אפשר לקשר לשירות מרכיב אחר על ידי העברת Intent אל bindService(). מידע נוסף זמין במדריך Services.

  • שידור של שידור חי

    שידור הוא הודעה שכל אפליקציה יכולה לקבל. המערכת משדרת שידורים שונים של אירועי מערכת, למשל כשהמערכת מופעלת או שהמכשיר מתחיל לטעון. כדי להעביר שידור לאפליקציות אחרות, מעבירים את הערך Intent ל-sendBroadcast() או ל-sendOrderedBroadcast().

בהמשך הדף נסביר איך פועלות כוונות ואיך משתמשים בהן. מידע נוסף זמין במאמרים אינטראקציה עם אפליקציות אחרות ושיתוף תוכן.

סוגי הכוונות

יש שני סוגים של כוונות:

  • כוונות מפורשות מציינות איזה רכיב של איזו אפליקציה יעמוד בכוונה, על ידי ציון ComponentName מלא. בדרך כלל משתמשים ב-Intent מפורש כדי להפעיל רכיב באפליקציה שלכם, כי אתם יודעים את שם הכיתה של הפעילות או השירות שאתם רוצים להפעיל. לדוגמה, אפשר להתחיל פעילות חדשה באפליקציה בתגובה לפעולה של משתמש, או להפעיל שירות להורדת קובץ ברקע.
  • אובייקטים מסוג Intent מרומז לא מציינים רכיב ספציפי, אלא מגדירים פעולה כללית לביצוע, שמאפשרת לרכיב מאפליקציה אחרת לטפל בה. לדוגמה, אם רוצים להציג למשתמש מיקום במפה, אפשר להשתמש בכוונה משתמעת כדי לבקש מאפליקציה אחרת עם יכולת כזו להציג מיקום מסוים במפה.

באיור 1 מוצג אופן השימוש בכוונה כשמתחילים פעילות. כשהמערכת מזהה באובייקט Intent שם של רכיב פעילות ספציפי, היא מפעילה את הרכיב הזה באופן מיידי.

איור 1. איך כוונה משתמעת מועברת דרך המערכת כדי להתחיל פעילות אחרת: [1] פעילות א' יוצרת Intent עם תיאור פעולה ומעבירה אותו אל startActivity(). [2] מערכת Android מחפשת בכל האפליקציות מסנן Intent שמתאים ל-Intent. כשהמערכת מוצאת התאמה, [3] היא מפעילה את הפעילות התואמת (פעילות ב') על ידי קריאה ל-method‏ onCreate() שלה והעברת הערך Intent.

כשמשתמשים ב-intent משתמע, מערכת Android מאתרת את הרכיב המתאים להפעלה על ידי השוואת התוכן של ה-intent למסנני ה-intent שהוגדרו בקובץ המניפסט של אפליקציות אחרות במכשיר. אם הכוונה תואמת למסנן כוונה, המערכת מפעילה את הרכיב הזה ומעבירה לו את האובייקט Intent. אם יש כמה מסנני כוונות תואמים, המערכת מציגה תיבת דו-שיח כדי שהמשתמש יוכל לבחור באפליקציה שבה הוא רוצה להשתמש.

מסנן כוונה הוא ביטוי בקובץ המניפסט של האפליקציה שמציין את סוג הכוונות שהרכיב רוצה לקבל. לדוגמה, הכרזה על מסנן כוונה לפעילות מאפשרת לאפליקציות אחרות להתחיל את הפעילות ישירות עם סוג מסוים של כוונה. באופן דומה, אם לא מגדירים מסנני כוונה לפעילות, אפשר להפעיל אותה רק עם כוונה מפורשת.

זהירות: כדי לוודא שהאפליקציה מאובטחת, תמיד צריך להשתמש בכוונה מפורשת כשמפעילים Service ולא להצהיר על מסנני כוונה לשירותים. שימוש בכוונה משתמעת כדי להפעיל שירות הוא סיכון אבטחה, כי אי אפשר לדעת איזה שירות יגיב לכוונה, והמשתמש לא יכול לראות איזה שירות מופעל. החל מגרסה 5.0 של Android (רמת API‏ 21), המערכת תשליך חריגה אם תפעילו את bindService() עם כוונה משתמעת.

בניית כוונת שימוש

אובייקט Intent מכיל מידע שמערכת Android משתמשת בו כדי לקבוע איזה רכיב להפעיל (למשל, שם הרכיב המדויק או קטגוריית הרכיב שצריכה לקבל את ה-Intent), וגם מידע שרכיב הנמען משתמש בו כדי לבצע את הפעולה בצורה תקינה (למשל, הפעולה שצריך לבצע והנתונים שעליהם צריך לבצע את הפעולה).

המידע העיקרי שמופיע ב-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 למצוא את הרכיב הטוב ביותר לקבלת ה-intent. עם זאת, לפעמים אפשר להסיק את סוג ה-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 לקבוע איזה רכיב של האפליקציה צריך להפעיל. עם זאת, כוונה יכולה להכיל מידע נוסף שלא משפיע על האופן שבו היא מנותבת לרכיב של האפליקציה. כוונה יכולה גם לספק את הפרטים הבאים:

Extras
צמדי מפתח/ערך שכוללים מידע נוסף שנחוץ לביצוע הפעולה המבוקשת. בדומה לפעולות מסוימות שמשתמשות בסוגים מסוימים של URI של נתונים, פעולות מסוימות משתמשות גם באפשרויות נוספות ספציפיות.

אפשר להוסיף נתונים נוספים באמצעות שיטות שונות של putExtra(), שכל אחת מהן מקבלת שני פרמטרים: שם המפתח והערך. אפשר גם ליצור אובייקט Bundle עם כל הנתונים הנוספים, ואז להוסיף את Bundle ל-Intent באמצעות putExtras().

לדוגמה, כשיוצרים כוונה לשליחת אימייל באמצעות ACTION_SEND, אפשר לציין את הנמען to באמצעות המפתח 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. לכן, ה-intent הזה מפעיל במפורש את הכיתה DownloadService באפליקציה.

מידע נוסף על פיתוח והפעלה של שירותים זמין במדריך Services.

דוגמה לאובייקט Intent מרומז

כוונה משתמעת מציינת פעולה שיכולה להפעיל כל אפליקציה במכשיר שיכולה לבצע את הפעולה. כדאי להשתמש בכוונה משתמעת כשהאפליקציה לא יכולה לבצע את הפעולה, אבל סביר להניח שאפליקציות אחרות יכולות, ואתם רוצים שהמשתמש יבחר באפליקציה שבה הוא רוצה להשתמש.

לדוגמה, אם יש לכם תוכן שאתם רוצים שהמשתמש ישתף עם אנשים אחרים, תוכלו ליצור כוונה עם הפעולה 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, כדי שהמשתמש יוכל לבחור באפליקציה שבה הוא רוצה להשתמש.

מידע נוסף על הפעלת אפליקציות אחרות זמין גם במדריך בנושא שליחת המשתמש לאפליקציה אחרת.

איור 2. תיבת דו-שיח לבחירה.

איך מאלצים את המערכת להציג בורר אפליקציות

אם יש יותר מאפליקציה אחת שתגיב לכוונתכם המשתמעת, המשתמש יוכל לבחור באפליקציה שבה הוא רוצה להשתמש ולהגדיר אותה כברירת המחדל לביצוע הפעולה. היכולת לבחור ברירת מחדל שימושית כשמבצעים פעולה שבה המשתמש רוצה להשתמש באותה אפליקציה בכל פעם, למשל פתיחת דף אינטרנט (לרוב המשתמשים מעדיפים להשתמש רק בדפדפן אינטרנט אחד).

עם זאת, אם כמה אפליקציות יכולות להגיב לכוונה, והמשתמש עשוי לרצות להשתמש באפליקציה אחרת בכל פעם, צריך להציג תיבת דו-שיח לבחירה באופן מפורש. בתיבת הדו-שיח לבחירה, המשתמש יתבקש לבחור באפליקציה שבה יתבצע הפעולה (המשתמש לא יכול לבחור אפליקציית ברירת מחדל לפעולה). לדוגמה, כשהאפליקציה מבצעת פעולת 'שיתוף' באמצעות הפעולה ACTION_SEND, יכול להיות שהמשתמשים ירצו לשתף באמצעות אפליקציה אחרת, בהתאם למצב הנוכחי שלהם. לכן, תמיד צריך להשתמש בתיבת הדו-שיח לבחירה, כפי שמוצג באיור 2.

כדי להציג את הבורר, יוצרים Intent באמצעות createChooser() ומעבירים אותו אל startActivity(), כפי שמתואר בדוגמה הבאה. בדוגמה הזו מוצגת תיבת דו-שיח עם רשימה של אפליקציות שתגובה לכוונה (intent) שהועברה לשיטה 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 (רמת API 31 ואילך) יש תכונת ניפוי באגים שמזהירה אם האפליקציה מבצעת הפעלה לא בטוחה של כוונה. לדוגמה, יכול להיות שהאפליקציה תפעיל באופן לא בטוח כוונת שימוש בתצוגת עץ, שהיא כוונת שימוש שמועברת כפריט נוסף בכוונת שימוש אחרת.

אם האפליקציה מבצעת את שתי הפעולות הבאות, המערכת מזהה הפעלה לא בטוחה של כוונה, ומתרחשת הפרה של StrictMode:

  1. האפליקציה מפרקת את ה-intent המוטמע מהפרטים הנוספים של ה-intent שנשלח.
  2. האפליקציה מפעילה באופן מיידי רכיב של האפליקציה באמצעות הכוונה המוטמעת הזו, למשל העברת הכוונה אל startActivity(),‏ startService() או bindService().

בפוסט בבלוג בנושא Android Nesting Intents ב-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());
}

שימוש אחראי יותר בכוונות

כדי למזער את הסיכוי להפעלה לא בטוחה של כוונה (intent) ולהפרה של StrictMode, כדאי לפעול לפי השיטות המומלצות הבאות.

כדאי להעתיק רק את התוספים החיוניים בתוך הכוונות, ולבצע את כל פעולות הניקוי והאימות הנדרשות. יכול להיות שהאפליקציה תעתיק את התוספים מ-Intent אחד ל-Intent אחר שמשמש להפעלת רכיב חדש. המצב הזה מתרחש כשהאפליקציה מבצעת קריאה ל-putExtras(Intent) או ל-putExtras(Bundle). אם האפליקציה מבצעת אחת מהפעולות האלה, צריך להעתיק רק את הנתונים הנוספים שהרכיב המקבל מצפה להם. אם הכוונה השנייה (שמתקבל בה העותק) מפעילה רכיב שלא מיוצא, צריך לנקות את הנתונים הנוספים ולאמת אותם לפני שמעתיק אותם לכוונה שמפעילה את הרכיב.

לא מייצאים את הרכיבים של האפליקציה ללא צורך. לדוגמה, אם אתם מתכוונים להפעיל רכיב של אפליקציה באמצעות כוונה פנימית בתצוגת עץ, צריך להגדיר את המאפיין android:exported של הרכיב הזה כ-false.

משתמשים ב-PendingIntent במקום בכוונה מוצגת בתצוגת עץ. כך, כשאפליקציה אחרת פותחת את החבילה של PendingIntent ב-Intent שמכיל אותה, האפליקציה האחרת יכולה להפעיל את PendingIntent באמצעות הזהות של האפליקציה שלכם. ההגדרה הזו מאפשרת לאפליקציה האחרת להפעיל בבטחה כל רכיב באפליקציה שלכם, כולל רכיב שלא יוצאו.

בתרשים 2 מוצג איך המערכת מעבירה את השליטה מאפליקציית הלקוח לאפליקציית שירות אחרת, ובחזרה לאפליקציה:

  1. האפליקציה יוצרת כוונה שמפעילה פעילות באפליקציה אחרת. בתוך הכוונה הזו, מוסיפים אובייקט PendingIntent כפריט נוסף. ה-intent בהמתנה מפעיל רכיב באפליקציה. הרכיב הזה לא מיוצא.
  2. כשהאפליקציה השנייה מקבלת את ה-Intent של האפליקציה שלכם, היא מחלצת את האובייקט PendingIntent שמוטמע בתוך האובייקט.
  3. האפליקציה האחרת מפעילה את השיטה send() באובייקט PendingIntent.
  4. אחרי העברת השליטה חזרה לאפליקציה, המערכת מפעילה את הכוונה בהמתנה באמצעות ההקשר של האפליקציה.

איור 2. תרשים של תקשורת בין אפליקציות כשמשתמשים בכוונה מושהית בתצוגת עץ.

קבלת אובייקט Intent מרומז

כדי לפרסם את הכוונות המשתמעות שהאפליקציה יכולה לקבל, מגדירים מסנן אחד או יותר של כוונות לכל אחד מרכיבי האפליקציה באמצעות רכיב <intent-filter> בקובץ המניפסט. כל מסנן כוונה מציין את סוג הכוונה שהוא מקבל על סמך הפעולה, הנתונים והקטגוריה של הכוונה. המערכת מעבירה כוונה משתמעת לרכיב האפליקציה רק אם היא יכולה לעבור דרך אחד מסנני הכוונה.

הערה: כוונה מפורשת תמיד מועברת ליעד שלה, ללא קשר למסנני הכוונה שהרכיב מצהיר עליהם.

רכיב אפליקציה צריך להצהיר על פילטרים נפרדים לכל משימה ייחודית שהוא יכול לבצע. לדוגמה, לפעילות אחת באפליקציית גלריית תמונות יכולים להיות שני פילטרים: מסנן אחד להצגת תמונה ומסנן אחר לעריכת תמונה. כשהפעילות מתחילה, היא בודקת את Intent ומחליטה איך לפעול על סמך המידע ב-Intent (למשל, להציג את אמצעי הבקרה של העורך או לא).

כל מסנן Intent מוגדר באמצעות רכיב <intent-filter> בקובץ המניפסט של האפליקציה, שמוטמע ברכיב האפליקציה התואם (למשל, רכיב <activity>).

בכל רכיב של האפליקציה שכולל רכיב <intent-filter>, צריך להגדיר ערך מפורש ל-android:exported. המאפיין הזה מציין אם אפליקציות אחרות יכולות לגשת לרכיב של האפליקציה. במצבים מסוימים, כמו פעילויות שמסנני הכוונה שלהן כוללים את הקטגוריה LAUNCHER, כדאי להגדיר את המאפיין הזה לערך true. אחרת, מומלץ להגדיר את המאפיין הזה לערך false.

אזהרה: אם פעילות, שירות או מקלט שידורים באפליקציה שלכם משתמשים במסנני Intent ולא מגדירים באופן מפורש את הערך של android:exported, לא תוכלו להתקין את האפליקציה במכשיר עם Android מגרסה 12 ואילך.

בתוך <intent-filter>, אפשר לציין את סוג הכוונות לקבלה באמצעות אחד או יותר משלושת הרכיבים הבאים:

<action>
הצהרה על פעולת הכוונה שאושרה, במאפיין name. הערך חייב להיות הערך המילולי של מחרוזת הפעולה, ולא קבוע הכיתה.
<data>
הצהרה על סוג הנתונים המקובל, באמצעות מאפיין אחד או יותר שמציינים היבטים שונים של URI הנתונים (scheme, ‏ host, ‏ port,‏ path) וסוג ה-MIME.
<category>
הצהרה על קטגוריית הכוונה שאושרה, במאפיין name. הערך חייב להיות ערך המחרוזת המילולית של פעולה, ולא קבוע הכיתה.

הערה: כדי לקבל כוונות משתמשים מרומזות, צריך לכלול את הקטגוריה CATEGORY_DEFAULT במסנן ה-Intent. השיטות startActivity() ו-startActivityForResult() מתייחסות לכל הכוונות כאילו הן הצהירו על הקטגוריה CATEGORY_DEFAULT. אם לא תצהירו על הקטגוריה הזו במסנן ה-Intent, לא יתבצע תיקוף של כוונות משתמשים מרומזות לפעילות שלכם.

לדוגמה, הנה הצהרת פעילות עם מסנן כוונה לקבלת כוונה 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 לא תעביר את ה-intent לרכיב. עם זאת, מכיוון שלרכיב יכולים להיות כמה מסנני כוונה, כוונה שלא עוברת דרך אחד מהמסננים של הרכיב עשויה לעבור דרך מסנן אחר. מידע נוסף על האופן שבו המערכת פותרת את הכוונות מפורט בקטע פתרון כוונות שבהמשך.

זהירות: שימוש במסנן אינטנטים הוא לא דרך מאובטחת למנוע מאפליקציות אחרות להפעיל את הרכיבים שלכם. אמנם מסנני Intent מגבילים את הרכיב להגיב רק לסוגים מסוימים של כוונות מרומזות, אבל אפליקציה אחרת יכולה להפעיל את רכיב האפליקציה באמצעות כוונה מפורשת אם המפתח קובע את שמות הרכיבים. אם חשוב לכם שרק האפליקציה שלכם תוכל להפעיל אחד מהרכיבים, אל תצהירו על מסנני כוונה במניפסט. במקום זאת, צריך להגדיר את המאפיין 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 מציינת שצריך להציב את הסמל של הפעילות הזו במרכז האפליקציות של המערכת. אם לא צוין סמל באמצעות icon ברכיב <activity>, המערכת משתמשת בסמל מהרכיב <application>.

צריך להתאים ביניהם כדי שהפעילות תופיע במרכז האפליקציות.

הפעילות השנייה, ShareActivity, מיועדת להקל על שיתוף טקסט ותוכן מדיה. המשתמשים יכולים להיכנס לפעילות הזו על ידי ניווט אליה מ-MainActivity, אבל הם יכולים גם להיכנס ל-ShareActivity ישירות מאפליקציה אחרת שמנפיקה כוונה משתמעת שתואמת לאחד משני מסנני הכוונה.

הערה: סוג ה-MIME, application/vnd.google.panorama360+jpg, הוא סוג נתונים מיוחד שמציין תמונות פנורמיות. אפשר לטפל בתמונות כאלה באמצעות ממשקי ה-API של Google Panorama.

התאמת כוונות למסנני כוונה של אפליקציות אחרות

אם אפליקציה אחרת מטרגטת ל-Android 13 (רמת API 33) ואילך, היא יכולה לטפל בכוונה של האפליקציה שלכם רק אם הכוונה תואמת לפעולות ולקטגוריות של רכיב <intent-filter> באפליקציה האחרת. אם המערכת לא מוצאת התאמה, היא גורמת להפעלת השגיאה ActivityNotFoundException. אפליקציית השליחה צריכה לטפל בחריגה הזו.

באופן דומה, אם תעדכנו את האפליקציה כך שתתמקד ב-Android 13 ואילך, כל הכוונות שמקורן באפליקציות חיצוניות יועברו לרכיב מיוצא של האפליקציה רק אם הכוונה תואמת לפעולות ולקטגוריות של רכיב <intent-filter> שהאפליקציה מצהירה עליו. ההתנהגות הזו מתרחשת ללא קשר לגרסת ה-SDK היעד של האפליקציה השולחת.

במקרים הבאים, אי אפשר לאכוף התאמה לכוונה:

  • כוונות (intents) שנשלחות לרכיבים שלא מגדירים מסנני כוונות.
  • כוונות שמקורן באותה אפליקציה.
  • כוונות שמקורן במערכת, כלומר כוונות שנשלחות מ-'system UID'‏ (uid=1000). אפליקציות המערכת כוללות את system_server ואפליקציות שמגדירות את android:sharedUserId לערך android.uid.system.
  • כוונות שמקורן ברמה הבסיסית (root).

מידע נוסף על התאמה לפי כוונת החיפוש

שימוש ב-intent בהמתנה

אובייקט PendingIntent הוא עטיפה של אובייקט Intent. המטרה העיקרית של PendingIntent היא להעניק לאפליקציה חיצונית הרשאה להשתמש ב-Intent שמכיל אותה, כאילו הוא הופעל מהתהליך של האפליקציה שלכם.

תרחישים לדוגמה שבהם כדאי להשתמש ב-intent בהמתנה:

  • הצהרת כוונה לביצוע פעולה כשהמשתמש מבצע פעולה עם ההתראה (ה-NotificationManager של מערכת Android מפעיל את ה-Intent).
  • הכרזה על כוונה לביצוע פעולה כשהמשתמש מבצע פעולה באמצעות הווידג'ט של האפליקציה (אפליקציית מסך הבית מבצעת את Intent).
  • הצהרת כוונה לביצוע בזמן עתידי מסוים (ה-AlarmManager של מערכת Android מפעיל את ה-Intent).

בדומה לכל אובייקט Intent שמיועד לטיפול על ידי סוג ספציפי של רכיב אפליקציה (Activity,‏ Service או BroadcastReceiver), כך גם צריך ליצור PendingIntent תוך התחשבות באותו העיקרון. כשמשתמשים ב-intent בהמתנה, האפליקציה לא מבצעת את ה-intent באמצעות קריאה כמו startActivity(). במקום זאת, צריך להצהיר על סוג הרכיב המיועד כשיוצרים את PendingIntent על ידי קריאה לשיטת היצירה המתאימה:

אלא אם האפליקציה שלכם מקבלת כוונות בהמתנה מאפליקציות אחרות, סביר להניח שהשיטות שלמעלה ליצירת PendingIntent הן השיטה היחידה של PendingIntent שתצטרכו.

כל שיטה מקבלת את האפליקציה הנוכחית Context, את ה-Intent שרוצים לעטוף וסימון אחד או יותר שמציינים איך להשתמש בכוונה (למשל, אם אפשר להשתמש בכוונה יותר מפעם אחת).

מידע נוסף על שימוש בכוונות בהמתנה זמין במסמכי העזרה של כל תרחיש לדוגמה, למשל במדריכי ה-API של התראות ושל ווידג'טים של אפליקציות.

ציון יכולת השינוי

אם האפליקציה שלכם מטרגטת ל-Android מגרסה 12 ואילך, עליכם לציין את יכולת ההשתנות של כל אובייקט 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() או לממשקי API דומים. האובייקט הניתן לשינוי PendingIntent מאפשר למערכת להוסיף פרטים נוספים של כוונת השימוש שמייצגים אירועים במחזור החיים של המיקום. האירועים האלה כוללים שינוי במיקום וספק שזמין.
  • תזמון התראות באמצעות AlarmManager. אובייקט PendingIntent שאפשר לשנות מאפשר למערכת להוסיף את התוסף של הכוונה EXTRA_ALARM_COUNT. הפרמטר הזה מייצג את מספר הפעמים שהתעוררתם מהתראה חוזרת. הוספת הפרמטר הזה מאפשרת ל-Intent להודיע לאפליקציה בצורה מדויקת אם ההתראה החוזרת הופעלה כמה פעמים, למשל כשהמכשיר היה במצב שינה.

אם האפליקציה יוצרת אובייקט PendingIntent שניתן לשינוי, מומלץ מאוד להשתמש בכוונת (intent) מפורשת ולמלא את השדה ComponentName. כך, בכל פעם שאפליקציה אחרת מפעילה את PendingIntent ומעבירה את השליטה בחזרה לאפליקציה שלכם, תמיד מופעל אותו הרכיב באפליקציה.

שימוש באובייקטי Intent מפורשים בתוך אובייקטי Intent בהמתנה

כדי להגדיר בצורה טובה יותר איך אפליקציות אחרות יכולות להשתמש ב-Intents בהמתנה של האפליקציה, תמיד צריך לעטוף Intent בהמתנה בIntent מפורש. כדי לפעול לפי השיטה המומלצת הזו, צריך לבצע את הפעולות הבאות:

  1. בודקים ששדות הפעולה, החבילה והרכיב של ה-Intent הבסיסי מוגדרים.
  2. כדי ליצור כוונות בהמתנה, אפשר להשתמש ב-FLAG_IMMUTABLE, שנוסף ב-Android 6.0 (רמת API ‏23). הדגל הזה מונעת מאפליקציות שקיבלו PendingIntent למלא נכסים שלא מולאו. אם הערך של minSdkVersion באפליקציה שלכם הוא 22 או קטן ממנו, תוכלו לספק בטיחות ותאימות יחד באמצעות הקוד הבא:

    if (Build.VERSION.SDK_INT >= 23) {
      // Create a PendingIntent using FLAG_IMMUTABLE.
    } else {
      // Existing code that creates a PendingIntent.
    }

פתרון הכוונה

כשהמערכת מקבלת כוונה משתמעת להתחיל פעילות, היא מחפשת את הפעילות הטובה ביותר לכוונה על ידי השוואה שלה למסנני כוונות על סמך שלושה היבטים:

  • פעולה.
  • נתונים (URI וסוג נתונים).
  • קטגוריה.

בקטעים הבאים מוסבר איך מתבצעת ההתאמה של כוונות לרכיבים המתאימים בהתאם להצהרה על מסנן ה-Intent בקובץ המניפסט של האפליקציה.

בדיקת פעולה

כדי לציין את פעולות ה-Intent הקבילות, מסנן Intent יכול להצהיר על אפס או יותר רכיבי <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, ו-Intent עדיין עובר. לכן, כוונה ללא קטגוריות תמיד עוברת את הבדיקה הזו, ללא קשר לקטגוריות שצוינו במסנן.

הערה: מערכת Android מחילה באופן אוטומטי את הקטגוריה CATEGORY_DEFAULT על כל כוונת השימוש המשתמעת שמועברת אל startActivity() ו-startActivityForResult(). אם אתם רוצים שהפעילות תקבל כוונות מרומזות, היא צריכה לכלול קטגוריה עבור "android.intent.category.DEFAULT" במסנני ה-Intent שלה, כפי שמוצג בדוגמה הקודמת של <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 בכוונה ל-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. ההתאמה מתבצעת רק אם הפעולות והקטגוריות ב-Intent תואמות למסנן, כפי שמתואר במסמכים של הכיתה IntentFilter.

האפליקציה שלכם יכולה להשתמש בהתאמת כוונות באופן דומה לאופן שבו אפליקציית Home משתמשת בה. ל-PackageManager יש קבוצה של שיטות query...() שמחזירות את כל הרכיבים שיכולים לקבל כוונת שימוש מסוימת, וקבוצה דומה של שיטות resolve...() שמגדירות את הרכיב הטוב ביותר להגיב לכוונת השימוש. לדוגמה, הפונקציה queryIntentActivities() מחזירה רשימה של כל הפעילויות שיכולות לבצע את הכוונה (intent) שהועברה כארגומנטים, והפונקציה queryIntentServices() מחזירה רשימה דומה של שירותים. אף אחת מהשיטות לא מפעילה את הרכיבים, אלא רק מציגה את הרכיבים שיכולים להגיב. יש שיטה דומה, queryBroadcastReceivers(), למקלטי שידורים.