IntentIntent הוא אובייקט הודעה שאפשר להשתמש בו כדי לבקש פעולה מרכיב אחר באפליקציה.
אובייקטים מסוג 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(). מידע נוסף זמין במדריך בנושא שירותים. - איך משדרים שידור
שידור הוא הודעה שכל אפליקציה יכולה לקבל. המערכת מספקת שידורים שונים של אירועי מערכת, למשל כשהמערכת מופעלת או כשהמכשיר מתחיל להיטען. אפשר להעביר שידור לאפליקציות אחרות על ידי העברת
IntentאלsendBroadcast()או אלsendOrderedBroadcast().
בהמשך הדף מוסבר איך כוונות פועלות ואיך משתמשים בהן. מידע נוסף בנושא זמין במאמרים אינטראקציה עם אפליקציות אחרות ושיתוף תוכן.
סוגי כוונות
יש שני סוגים של כוונות:
- ב-Intents מפורשים מציינים איזה רכיב של איזו אפליקציה ימלא את ה-Intent, על ידי ציון
ComponentNameמלא. בדרך כלל משתמשים ב-Intent מפורש כדי להפעיל רכיב באפליקציה שלכם, כי אתם יודעים את שם המחלקה של הפעילות או השירות שאתם רוצים להפעיל. לדוגמה, יכול להיות שתתחילו פעילות חדשה באפליקציה בתגובה לפעולת משתמש, או שתתחילו שירות כדי להוריד קובץ ברקע. - אובייקטים מרומזים מסוג Intent לא מציינים רכיב ספציפי, אלא מצהירים על פעולה כללית לביצוע, וכך מאפשרים לרכיב מאפליקציה אחרת לטפל בהם. לדוגמה, אם רוצים להציג למשתמש מיקום במפה, אפשר להשתמש ביעד משתמע כדי לבקש מאפליקציה אחרת עם יכולת מתאימה להציג מיקום מסוים במפה.
איור 1 מראה איך משתמשים ב-Intent כשמתחילים פעילות. כששם האובייקט Intent מציין במפורש רכיב פעילות ספציפי, המערכת מפעילה את הרכיב הזה באופן מיידי.
איור 1. איך כוונה משתמעת מועברת דרך המערכת כדי להתחיל פעילות אחרת: [1] פעילות א' יוצרת Intent עם תיאור פעולה ומעבירה אותה אל startActivity(). [2] מערכת Android מחפשת בכל האפליקציות מסנן Intent שתואם ל-Intent. כשנמצאת התאמה, [3] המערכת מתחילה את פעילות ההתאמה (פעילות ב') על ידי הפעלת השיטה onCreate() והעברת Intent אליה.
כשמשתמשים ב-Intent משתמע, מערכת Android מוצאת את הרכיב המתאים להפעלה על ידי השוואת התוכן של ה-Intent למסנני ה-Intent שמוצהרים בקובץ המניפסט של אפליקציות אחרות במכשיר. אם הכוונה תואמת למסנן כוונות, המערכת מפעילה את הרכיב הזה ומעבירה לו את אובייקט Intent. אם יש כמה מסנני כוונות תואמים, המערכת מציגה תיבת דו-שיח כדי שהמשתמש יוכל לבחור באיזו אפליקציה להשתמש.
מסנן Intent הוא ביטוי בקובץ המניפסט של האפליקציה שמציין את סוגי ה-Intent שהרכיב רוצה לקבל. לדוגמה, אם מצהירים על מסנן כוונות לפעילות, אפליקציות אחרות יכולות להתחיל את הפעילות ישירות באמצעות כוונה מסוג מסוים. באופן דומה, אם לא מצהירים על מסנני כוונות לפעילות, אפשר להתחיל אותה רק באמצעות כוונה מפורשת.
זהירות: כדי לוודא שהאפליקציה מאובטחת, תמיד צריך להשתמש ב-intent מפורש כשמתחילים Service, ואסור להצהיר על מסנני intent לשירותים. שימוש ב-intent משתמע כדי להפעיל שירות הוא סיכון אבטחה, כי אי אפשר לדעת איזה שירות יגיב ל-intent, והמשתמש לא יכול לראות איזה שירות מופעל. החל מ-Android 5.0 (רמת API 21), המערכת זורקת חריגה אם קוראים ל-bindService() עם intent משתמע.
בניית כוונה
אובייקט Intent מכיל מידע שמערכת Android משתמשת בו כדי לקבוע איזה רכיב להפעיל (כמו השם המדויק של הרכיב או קטגוריית הרכיב שאליו צריך להעביר את ה-Intent), וגם מידע שרכיב היעד משתמש בו כדי לבצע את הפעולה בצורה תקינה (כמו הפעולה שיש לבצע והנתונים שעליהם צריך לפעול).
המידע העיקרי שכלול ב-Intent הוא:
- שם הרכיב
- השם של הרכיב שרוצים להפעיל.
זהו פרמטר אופציונלי, אבל הוא המידע החשוב ביותר שגורם ל-Intent להיות מפורש, כלומר ה-Intent צריך להימסר רק לרכיב האפליקציה שמוגדר לפי שם הרכיב. אם לא מציינים שם של רכיב, הכוונה היא משתמעת והמערכת מחליטה איזה רכיב צריך לקבל את הכוונה על סמך פרטי הכוונה האחרים (כמו הפעולה, הנתונים והקטגוריה – שמפורטים בהמשך). אם אתם צריכים להפעיל רכיב ספציפי באפליקציה, אתם צריכים לציין את שם הרכיב.
הערה: כשמפעילים
Service, תמיד צריך לציין את שם הרכיב. אחרת, אי אפשר לדעת בוודאות איזה שירות יגיב לכוונה, והמשתמש לא יכול לראות איזה שירות מופעל.השדה הזה של
Intentהוא אובייקטComponentName, שאפשר לציין באמצעות שם מחלקה מלא של רכיב היעד, כולל שם החבילה של האפליקציה, לדוגמה,com.example.ExampleActivity. אפשר להגדיר את שם הרכיב באמצעותsetComponent(), setClass(), setClassName()או באמצעות ה-constructorIntent. - פעולה
- מחרוזת שמציינת את הפעולה הגנרית לביצוע (למשל view או pick).
במקרה של כוונת שידור, זו הפעולה שהתרחשה ומדווחת. הפעולה קובעת במידה רבה את המבנה של שאר הכוונה – במיוחד את המידע שכלול בנתונים ובתוספים.
אתם יכולים להגדיר פעולות משלכם לשימוש ב-Intents באפליקציה (או לשימוש באפליקציות אחרות כדי להפעיל רכיבים באפליקציה), אבל בדרך כלל מגדירים קבועי פעולה שמוגדרים על ידי המחלקה
Intentאו מחלקות אחרות של Framework. הנה כמה פעולות נפוצות להתחלת פעילות:ACTION_VIEW- משתמשים בפעולה הזו ב-Intent עם
startActivity()כשיש מידע שפעילות יכולה להציג למשתמש, כמו תמונה לצפייה באפליקציית גלריה או כתובת לצפייה באפליקציית מפות. ACTION_SEND- הפעולה הזו נקראת גם share (שיתוף), וצריך להשתמש בה ב-intent עם
startActivity()כשרוצים לאפשר למשתמש לשתף נתונים באמצעות אפליקציה אחרת, כמו אפליקציית אימייל או אפליקציה לשיתוף ברשתות חברתיות.
במאמר
Intentclass reference מפורטים עוד קבועים שמגדירים פעולות כלליות. פעולות אחרות מוגדרות במקומות אחרים במסגרת 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, אפשר לציין את הנמען to באמצעות המפתחEXTRA_EMAIL, ואת הנושא subject באמצעות המפתחEXTRA_SUBJECT.המחלקות
Intentמציינות הרבה קבועים שלEXTRA_*לסוגי נתונים סטנדרטיים. אם אתם צריכים להצהיר על מפתחות נוספים משלכם (ל-Intents שהאפליקציה מקבלת), הקפידו לכלול את שם החבילה של האפליקציה כקידומת, כמו שמוצג בדוגמה הבאה: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 מפורש הוא Intent שמשמש להפעלת רכיב ספציפי באפליקציה, כמו פעילות או שירות מסוימים באפליקציה. כדי ליצור Intent מפורש, מגדירים את שם הרכיב לאובייקט Intent – כל מאפייני ה-Intent האחרים הם אופציונליים.
לדוגמה, אם יצרתם שירות באפליקציה בשם DownloadService, שמיועד להורדת קובץ מהאינטרנט, תוכלו להפעיל אותו באמצעות הקוד הבא:
Kotlin
// Executed in an Activity, so 'this' is theContext// The fileUrl is a string URL, such as "http://www.example.com/image.png" val downloadIntent = Intent(this, DownloadService::class.java).apply { data =Uri.parse(fileUrl) } startService(downloadIntent)
Java
// Executed in an Activity, so 'this' is theContext// The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse(fileUrl)); startService(downloadIntent);
הקונסטרוקטור Intent(Context, Class) מספק לאפליקציה Context ולרכיב אובייקט Class. לכן, הכוונה הזו מפעילה במפורש את המחלקה DownloadService באפליקציה.
מידע נוסף על בנייה והפעלה של שירות זמין במדריך בנושא שירותים.
דוגמה לאובייקט Intent מרומז
אובייקט Intent מרומז מציין פעולה שיכולה להפעיל כל אפליקציה במכשיר שיכולה לבצע את הפעולה. שימוש ב-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(), המערכת בודקת את כל האפליקציות המותקנות כדי לקבוע אילו מהן יכולות לטפל בסוג הזה של Intent (Intent עם הפעולה ACTION_SEND ועם הנתונים text/plain). אם יש רק אפליקציה אחת שיכולה לטפל בבקשה, האפליקציה הזו תיפתח מיד ותקבל את הכוונה. אם אף אפליקציה אחרת לא יכולה לטפל בה, האפליקציה שלכם יכולה לזהות את השגיאה 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 (רמת API 31) ואילך יש תכונת ניפוי באגים שמזהירה אתכם אם האפליקציה מפעילה כוונה בצורה לא בטוחה. לדוגמה, האפליקציה שלך עשויה להפעיל בצורה לא בטוחה intent מוטבע, שהוא intent שמועבר כתוספת ב-intent אחר.
אם האפליקציה מבצעת את שתי הפעולות הבאות, המערכת מזהה הפעלה לא בטוחה של intent, ומתרחשת הפרה של StrictMode:
- האפליקציה שלך מבטלת את האריזה של intent מקונן מתוך התוספים של intent שנמסר.
- האפליקציה שלך מפעילה באופן מיידי רכיב של האפליקציה באמצעות הכוונה המקוננת הזו, למשל העברת הכוונה אל
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).
אם האפליקציה שלכם מבצעת אחת מהפעולות האלה, צריך להעתיק רק את התוספים שהרכיב המקבל מצפה להם. אם ה-Intent השני (שמקבל את העותק) מפעיל רכיב שלא יוצא, צריך לבצע סניטציה ואימות של התוספים לפני שמעתיקים אותם ל-Intent שמפעיל את הרכיב.
אל תייצאו רכיבים של האפליקציה שלא לצורך. לדוגמה, אם אתם רוצים להפעיל רכיב של אפליקציה באמצעות אובייקט Intent פנימי מוטמע, צריך להגדיר את מאפיין android:exported של הרכיב הזה לערך false.
משתמשים בPendingIntent במקום בכוונת משנה. כך, כש-PendingIntent של Intent שמכיל אותו מפורק על ידי אפליקציה אחרת, האפליקציה האחרת יכולה להפעיל את PendingIntent באמצעות הזהות של האפליקציה שלכם. ההגדרה הזו מאפשרת לאפליקציה האחרת להפעיל בבטחה כל רכיב, כולל רכיב שלא מיוצא, באפליקציה שלכם.
בתרשים באיור 2 מוצג אופן העברת השליטה מהאפליקציה שלכם (הלקוח) לאפליקציה אחרת (השירות) וחזרה לאפליקציה שלכם:
- האפליקציה יוצרת intent שמפעיל פעילות באפליקציה אחרת. ב-intent הזה, מוסיפים אובייקט
PendingIntentכתוספת. ה-PendingIntent הזה מפעיל רכיב באפליקציה שלך; הרכיב הזה לא מיוצא. - כשמתקבל ה-Intent של האפליקציה, האפליקציה השנייה מחלצת את אובייקט
PendingIntentהמקונן. - האפליקציה השנייה מפעילה את השיטה
send()באובייקטPendingIntent. - אחרי שהמערכת מחזירה את השליטה לאפליקציה, היא מפעילה את ה-intent בהמתנה באמצעות ההקשר של האפליקציה.
איור 2. תרשים של תקשורת בין אפליקציות כשמשתמשים ב-pending intent מוטמע.
קבלת אובייקט Intent מרומז
כדי לפרסם אילו Intents מרומזים האפליקציה יכולה לקבל, צריך להצהיר על מסנן Intent אחד או יותר לכל אחד מרכיבי האפליקציה באמצעות רכיב <intent-filter> בקובץ המניפסט.
כל מסנן כוונות מציין את סוגי הכוונות שהוא מקבל על סמך הפעולה, הנתונים והקטגוריה של הכוונה. המערכת מעבירה מנגנון Intent משתמע לרכיב האפליקציה רק אם מנגנון ה-Intent יכול לעבור דרך אחד ממסנני ה-Intent.
הערה: אובייקט Intent מפורש תמיד מועבר ליעד שלו, ללא קשר למסנני Intent שהרכיב מצהיר עליהם.
רכיב אפליקציה צריך להצהיר על פילטרים נפרדים לכל משימה ייחודית שהוא יכול לבצע.
לדוגמה, לפעילות אחת באפליקציית גלריית תמונות יכולים להיות שני פילטרים: פילטר אחד
להצגת תמונה ופילטר אחר לעריכת תמונה. כשהפעילות מתחילה, היא בודקת את Intent ומחליטה איך להתנהג על סמך המידע ב-Intent (למשל, אם להציג את אמצעי הבקרה של העורך או לא).
כל מסנן Intent מוגדר על ידי רכיב <intent-filter> בקובץ המניפסט של האפליקציה, שמוטמע ברכיב האפליקציה המתאים (כמו רכיב <activity>).
בכל רכיב של אפליקציה שכולל רכיב <intent-filter>, צריך להגדיר ערך באופן מפורש ל-android:exported.
המאפיין הזה מציין אם רכיב האפליקציה נגיש לאפליקציות אחרות. במקרים מסוימים, כמו פעילויות שמסנני ה-Intent שלהן כוללים את הקטגוריה LAUNCHER, כדאי להגדיר את המאפיין הזה לערך true. אחרת, עדיף להגדיר את המאפיין הזה לערך false.
אזהרה: אם פעילות, שירות או מקלט שידורים באפליקציה שלך משתמשים במסנני Intent ולא מגדירים במפורש את הערך של android:exported, אי אפשר יהיה להתקין את האפליקציה במכשיר עם Android 12 ואילך.
בתוך התג <intent-filter>, אפשר לציין את סוג הכוונות לקבל באמצעות אחד או יותר משלושת הרכיבים האלה:
<action>
- ההצהרה על פעולת ה-Intent שהתקבלה, במאפיין
name. הערך חייב להיות מחרוזת מילולית של פעולה, ולא קבוע המחלקה. <data>
- מגדיר את סוג הנתונים שמתקבלים באמצעות מאפיין אחד או יותר שמציינים היבטים שונים של URI של נתונים (
scheme,host,port,path) וסוג MIME. <category>- הצהרה על קטגוריית הכוונה שאושרה, במאפיין
name. הערך צריך להיות מחרוזת מילולית של פעולה, ולא קבוע המחלקה.הערה: כדי לקבל Intents משתמעים, צריך לכלול את הקטגוריה
CATEGORY_DEFAULTבמסנן ה-Intent. השיטותstartActivity()ו-startActivityForResult()מתייחסות לכל הכוונות כאילו הן הוגדרו בקטגוריהCATEGORY_DEFAULT. אם לא תצהירו על הקטגוריה הזו במסנן ה-Intent, לא יהיה אפשר לפתור אף 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 לא מאפשר למנוע מאפליקציות אחרות להפעיל את הרכיבים שלכם בצורה מאובטחת. למרות שמסנני Intent מגבילים את הרכיב כך שיגיב רק לסוגים מסוימים של Implicit Intents, אפליקציה אחרת יכולה להפעיל את רכיב האפליקציה באמצעות Explicit Intent אם המפתח קובע את שמות הרכיבים.
אם חשוב שרק האפליקציה שלכם תוכל להפעיל אחד מהרכיבים שלכם, אל תצהירו על מסנני Intent במניפסט. במקום זאת, צריך להגדיר את מאפיין exported לערך "false" עבור הרכיב הזה.
באופן דומה, כדי למנוע הפעלה לא מכוונת של Service של אפליקציה אחרת, תמיד צריך להשתמש ב-Intent מפורש כדי להפעיל את השירות שלכם.
הערה:
לכל הפעילויות, צריך להצהיר על מסנני הכוונות בקובץ המניפסט.
עם זאת, אפשר לרשום מסננים ל-broadcast receivers באופן דינמי על ידי קריאה ל-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.
התאמת כוונות למסנני Intent של אפליקציות אחרות
אם אפליקציה אחרת מטרגטת ל-Android 13 (רמת API 33) ומעלה, היא יכולה לטפל ב-Intent של האפליקציה שלכם רק אם ה-Intent תואם לפעולות ולסיווגים של רכיב <intent-filter> באפליקציה האחרת. אם המערכת לא מוצאת התאמה, היא מפעילה את ActivityNotFoundException.
אפליקציית השליחה צריכה לטפל בחריגה הזו.
באופן דומה, אם תעדכנו את האפליקציה כך שהיא תטרגט את Android מגרסה 13 ואילך, כל הכוונות שמקורן באפליקציות חיצוניות יועברו לרכיב מיוצא של האפליקציה רק אם הכוונה הזו תתאים לפעולות ולסיווגים של רכיב <intent-filter> שהאפליקציה מצהירה עליו. ההתנהגות הזו מתרחשת ללא קשר לגרסת ה-SDK שהאפליקציה השולחת מטרגטת.
במקרים הבאים, לא מתבצעת התאמה לכוונת החיפוש:
- Intents שנשלחים לרכיבים שלא מוגדרים בהם מסנני Intent.
- כוונה שמקורה באותה אפליקציה.
- כוונה שמקורה במערכת, כלומר כוונה שנשלחת מ'מזהה המשתמש של המערכת' (uid=1000). אפליקציות המערכת כוללות את
system_serverואפליקציות שהוגדר בהןandroid:sharedUserIdכ-android.uid.system. - כוונה שמקורה בשורש.
מידע נוסף על התאמה לפי כוונת המשתמש
שימוש בכוונת רכישה בהמתנה
אובייקט PendingIntent הוא מעטפת של אובייקט Intent. המטרה העיקרית של PendingIntent
היא להעניק הרשאה לאפליקציה חיצונית להשתמש ב-Intent שכלול בה כאילו היא הופעלה מהתהליך של האפליקציה שלכם.
תרחישי שימוש עיקריים ל-PendingIntent כוללים את הדברים הבאים:
- הצהרה על כוונה לביצוע כשמשתמש מבצע פעולה עם ההתראה (מערכת Android
NotificationManagerמבצעת אתIntent). - הצהרה על כוונה לביצוע פעולה כשמשתמש מבצע פעולה באמצעות הווידג'ט של האפליקציה (האפליקציה במסך הבית מבצעת את
Intent). - הצהרה על כוונה לביצוע בזמן עתידי מוגדר (מערכת Android
AlarmManagerמבצעת אתIntent).
בדיוק כמו שכל אובייקט Intent מיועד לטיפול על ידי סוג ספציפי של רכיב אפליקציה (Activity, Service או BroadcastReceiver), כך גם צריך ליצור PendingIntent תוך התחשבות באותו שיקול. כשמשתמשים ב-pending intent, האפליקציה לא מבצעת את ה-intent באמצעות קריאה כמו startActivity(). במקום זאת, צריך להצהיר על סוג הרכיב המיועד כשיוצרים את PendingIntent על ידי קריאה לשיטת היצירה המתאימה:
-
PendingIntent.getActivity()ל-IntentשמתחילActivity. -
PendingIntent.getService()ל-Intentשמתחיל ב-Service. -
PendingIntent.getBroadcast()ל-Intentשמתחיל ב-BroadcastReceiver.
אלא אם האפליקציה שלכם מקבלת כוונות בהמתנה מאפליקציות אחרות, סביר להניח שהשיטות שלמעלה ליצירת PendingIntent הן השיטות היחידות שתצטרכו להשתמש בהן.PendingIntent
כל שיטה מקבלת את האפליקציה הנוכחית Context, את Intent שרוצים לעטוף, ודגל אחד או יותר שמציינים איך צריך להשתמש ב-Intent (למשל, אם אפשר להשתמש ב-Intent יותר מפעם אחת).
מידע נוסף על שימוש ב-pending intents זמין במסמכי התיעוד של כל אחד מתרחישי השימוש הרלוונטיים, כמו במדריכי ה-API של Notifications ושל App Widgets.
ציון יכולת השינוי
אם האפליקציה שלכם מטרגטת ל-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. הנתון הנוסף הזה מייצג את מספר הפעמים שהופעלה אזעקה חוזרת. התוספת הזו מאפשרת להודיע לאפליקציה בצורה מדויקת אם התראה חוזרת הופעלה כמה פעמים, למשל כשהמכשיר היה במצב שינה.
אם האפליקציה יוצרת אובייקט PendingIntent שניתן לשינוי, מומלץ מאוד להשתמש בintent מפורש ולמלא את ComponentName. כך, בכל פעם שאפליקציה אחרת מפעילה את PendingIntent ומעבירה את השליטה בחזרה לאפליקציה שלכם, אותו רכיב באפליקציה שלכם תמיד מופעל.
שימוש באובייקטים מפורשים של Intent באובייקטים של Intent בהמתנה
כדי להגדיר בצורה טובה יותר איך אפליקציות אחרות יכולות להשתמש ב-pending intents של האפליקציה שלכם, תמיד כדאי להשתמש ב-pending intent מסביב ל-explicit intent. כדי לפעול לפי השיטה המומלצת הזו, צריך לעשות את הפעולות הבאות:
- בודקים שהשדות 'פעולה', 'חבילה' ו'רכיב' של Intent הבסיס מוגדרים.
-
כדי ליצור כוונות בהמתנה, צריך להשתמש ב-
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 מקובלות, מסנן 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 עדיין יעבור. לכן, Intent ללא קטגוריות תמיד עובר את הבדיקה הזו, ללא קשר לקטגוריות שמוצהרות במסנן.
הערה:
מערכת Android מחילה באופן אוטומטי את הקטגוריה CATEGORY_DEFAULT על כל הכוונות המרומזות שמועברות אל startActivity() ו-startActivityForResult().
אם רוצים שהפעילות תקבל מנגנוני Intent משתמעים, צריך לכלול קטגוריה של "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 שצוינו במסנן. הכללים הם:
- אינטנט שלא מכיל URI או סוג MIME עובר את הבדיקה רק אם המסנן לא מציין URI או סוג 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.
הערה: אם ב-Intent מצוינים 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>
התאמה לפי כוונת רכישה
התאמה של אובייקטים מסוג Intent למסנני Intent לא נועדה רק כדי לגלות רכיב יעד להפעלה, אלא גם כדי לגלות מידע על קבוצת הרכיבים במכשיר. לדוגמה, אפליקציית Home מאכלסת את מרכז האפליקציות על ידי איתור כל הפעילויות עם מסנני Intent שמציינים את הפעולה ACTION_MAIN ואת הקטגוריה CATEGORY_LAUNCHER.
ההתאמה תצליח רק אם הפעולות והקטגוריות ב-Intent יתאימו למסנן, כפי שמתואר במסמכי התיעוד של המחלקה IntentFilter.
האפליקציה שלכם יכולה להשתמש בהתאמה של כוונות באופן דומה לזה שבו אפליקציית Home עושה זאת.
ל-PackageManager יש קבוצה של query...()
שיטות שמחזירות את כל הרכיבים שיכולים לקבל כוונה מסוימת, וסדרה דומה של שיטות resolve...() שקובעות את הרכיב הכי טוב להגיב לכוונה. לדוגמה, הפונקציה queryIntentActivities() מחזירה רשימה של כל הפעילויות שיכולות לבצע את הכוונה שמועברת כארגומנט, והפונקציה queryIntentServices() מחזירה רשימה דומה של שירותים.
אף אחת מהשיטות לא מפעילה את הרכיבים, אלא רק מציגה את הרכיבים שיכולים להגיב. יש שיטה דומה, queryBroadcastReceivers(), למקלטי שידורים.