מילוי תרחישים לדוגמה נפוצים תוך חשיפה מוגבלת של חבילות

במסמך הזה מוצגים כמה תרחישי שימוש נפוצים שבהם אפליקציה מקיימת אינטראקציה עם אפליקציות אחרות. בכל סעיף שמתייחסת לאפליקציה מוסבר איך להפעיל את הפונקציונליות של האפליקציה עם הרשאות גישה מוגבלות של חבילות. ההוראות מפורטות אם האפליקציה מטרגטת את Android 11 (רמת API 30) ואילך.

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

אם חלק מהאפליקציה שלכם תלוי בידיעה אם הקריאה ל-startActivity() יכולה להצליח, למשל הצגת ממשק משתמש, צריך להוסיף רכיב לרכיב <queries> במניפסט של האפליקציה. בדרך כלל זהו רכיב <intent>.

פתיחת כתובות URL

בקטע הזה מתוארות דרכים שונות לפתיחת כתובות URL באפליקציה שמטרגטת ל-Android 11 ואילך.

פתיחת כתובות URL בדפדפן או באפליקציה אחרת

כדי לפתוח כתובת URL, צריך להשתמש ב-Intent שמכיל את פעולת ה-Intent ACTION_VIEW, כפי שמתואר במדריך לטעינת כתובת URL של אתר. אחרי שמפעילים את startActivity() באמצעות הכוונה הזו, מתרחשת אחת מהאפשרויות הבאות:

  • כתובת ה-URL נפתחת באפליקציית דפדפן אינטרנט.
  • כתובת ה-URL תיפתח באפליקציה שתומכת בכתובת ה-URL כקישור עומק.
  • תופיע תיבת דו-שיח להסרת עמימות, שמאפשרת למשתמש לבחור באפליקציה שתפעל את כתובת ה-URL.
  • השגיאה ActivityNotFoundException מתרחשת כי אין במכשיר אפליקציה שיכולה לפתוח את כתובת ה-URL. (זה חריג).

    מומלץ לאתר את הבעיה ActivityNotFoundException ולטפל בה באפליקציה אם היא מתרחשת.

מכיוון ששיטת startActivity() לא דורשת הרשאת גישה לחבילה כדי להפעיל פעילות של אפליקציה אחרת, אין צורך להוסיף אלמנט <queries> למניפסט של האפליקציה או לבצע שינויים באלמנט <queries> קיים. המצב הזה נכון גם לגבי כוונות משתמשים מרומזות וגם לגבי כוונות משתמשים מפורשות שפותחות כתובת URL.

איך בודקים אם דפדפן זמין

במקרים מסוימים, יכול להיות שהאפליקציה תצטרך לוודא שיש לפחות דפדפן אחד זמין במכשיר, או שדפדפן ספציפי הוא דפדפן ברירת המחדל, לפני שתנסה לפתוח כתובת URL. במקרים כאלה, צריך לכלול את הרכיב <intent> הבא כחלק מהרכיב <queries> במניפסט:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="https" />
</intent>

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

פתיחת כתובות URL בכרטיסיות מותאמות אישית

כרטיסיות בהתאמה אישית מאפשרות לאפליקציה להתאים אישית את המראה והתחושה של הדפדפן. אתם יכולים לפתוח כתובת URL בכרטיסייה בהתאמה אישית בלי להוסיף או לשנות את הרכיב <queries> במניפסט של האפליקציה.

עם זאת, כדאי לבדוק אם במכשיר יש דפדפן שתומך בכרטיסיות בהתאמה אישית או לבחור דפדפן ספציפי להפעלה עם כרטיסיות בהתאמה אישית באמצעות CustomTabsClient.getPackageName(). במקרים כאלה, צריך לכלול את האלמנט <intent> הבא כחלק מהאלמנט <queries> במניפסט:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>

איך מאפשרים לאפליקציות שאינן דפדפנים לטפל בכתובות URL

גם אם האפליקציה שלכם יכולה לפתוח כתובות URL באמצעות כרטיסיות בהתאמה אישית, מומלץ לאפשר לאפליקציה שאינה דפדפן לפתוח כתובת URL, אם אפשר. כדי לספק את היכולת הזו באפליקציה, צריך לנסות לבצע קריאה ל-startActivity() באמצעות כוונה שמגדירה את דגל הכוונה FLAG_ACTIVITY_REQUIRE_NON_BROWSER. אם המערכת תחזיר את הערך ActivityNotFoundException, האפליקציה תוכל לפתוח את כתובת ה-URL בכרטיסייה מותאמת אישית.

אם הכוונה כוללת את הדגל הזה, קריאה ל-startActivity() תגרום להשלכת ActivityNotFoundException כשאחד מהתנאים הבאים מתקיים:

  • השיחה הייתה מפעילה אפליקציית דפדפן ישירות.
  • במהלך השיחה, תוצג למשתמש תיבת דו-שיח להסרת עמימות, שבה האפשרויות היחידות הן אפליקציות דפדפן.

קטע הקוד הבא מראה איך לעדכן את הלוגיקה כך שתשתמש בדגל Intent FLAG_ACTIVITY_REQUIRE_NON_BROWSER:

Kotlin

try {
    val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply {
        // The URL should either launch directly in a non-browser app (if it's
        // the default) or in the disambiguation dialog.
        addCategory(CATEGORY_BROWSABLE)
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER
    }
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Only browser apps are available, or a browser is the default.
    // So you can open the URL directly in your app, for example in a
    // Custom Tab.
    openInCustomTabs(url)
}

Java

try {
    Intent intent = new Intent(ACTION_VIEW, Uri.parse(url));
    // The URL should either launch directly in a non-browser app (if it's the
    // default) or in the disambiguation dialog.
    intent.addCategory(CATEGORY_BROWSABLE);
    intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Only browser apps are available, or a browser is the default.
    // So you can open the URL directly in your app, for example in a
    // Custom Tab.
    openInCustomTabs(url);
}

הימנעות מתיבת דו-שיח להסרת עמימות

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

אם הכוונה כוללת את הדגל הזה, קריאה ל-startActivity() תגרום להשלכת ActivityNotFoundException במקרה שהקריאה הייתה מציגה למשתמש תיבת דו-שיח לצורך הסרת עמימות.

אם הכוונה כוללת גם את הדגל הזה וגם את דגל הכוונה FLAG_ACTIVITY_REQUIRE_NON_BROWSER, קריאה ל-startActivity() תגרום להשלכת ActivityNotFoundException כשאחד מהתנאים הבאים מתקיים:

  • השיחה תפעיל את אפליקציית הדפדפן ישירות.
  • במהלך השיחה, תוצג למשתמש תיבת דו-שיח לצורך הסרת עמימות.

קטע הקוד הבא מראה איך להשתמש בדגלים FLAG_ACTIVITY_REQUIRE_NON_BROWSER ו-FLAG_ACTIVITY_REQUIRE_DEFAULT ביחד:

Kotlin

val url = URL_TO_LOAD
try {
    // For this intent to be invoked, the system must directly launch a
    // non-browser app.
    val intent = Intent(ACTION_VIEW, Uri.parse(url)).apply {
        addCategory(CATEGORY_BROWSABLE)
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER or
                FLAG_ACTIVITY_REQUIRE_DEFAULT
    }
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // This code executes in one of the following cases:
    // 1. Only browser apps can handle the intent.
    // 2. The user has set a browser app as the default app.
    // 3. The user hasn't set any app as the default for handling this URL.
    openInCustomTabs(url)
}

Java

String url = URL_TO_LOAD;
try {
    // For this intent to be invoked, the system must directly launch a
    // non-browser app.
    Intent intent = new Intent(ACTION_VIEW, Uri.parse(url));
    intent.addCategory(CATEGORY_BROWSABLE);
    intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_REQUIRE_NON_BROWSER |
            FLAG_ACTIVITY_REQUIRE_DEFAULT);
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // This code executes in one of the following cases:
    // 1. Only browser apps can handle the intent.
    // 2. The user has set a browser app as the default app.
    // 3. The user hasn't set any app as the default for handling this URL.
    openInCustomTabs(url);
}

פתיחת קובץ

אם האפליקציה מטפלת בקבצים או בקבצים מצורפים, למשל אם המכשיר יכול לפתוח קובץ מסוים, בדרך כלל הכי קל להתחיל פעילות שיכולה לטפל בקובץ. כדי לעשות זאת, משתמשים בכוונה (intent) שכוללת את פעולת הכוונה ACTION_VIEW ואת ה-URI שמייצג את הקובץ הספציפי. אם אין אפליקציה זמינה במכשיר, האפליקציה שלכם יכולה לקבל את האירוע ActivityNotFoundException. בלוגיקת הטיפול בחריגים, תוכלו להציג שגיאה או לנסות לטפל בקובץ בעצמכם.

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

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
  <data android:mimeType="application/pdf" />
</intent>

לאחר מכן תוכלו לבדוק אם אפליקציה מסוימת זמינה על ידי קריאה ל-resolveActivity() עם הכוונה שלכם.

הענקת גישה ל-URI

הערה: חובה להצהיר על הרשאות גישה ל-URI כפי שמתואר בקטע הזה באפליקציות שמטרגטות את Android 11 (רמת API 30) ואילך, ומומלץ לעשות זאת בכל האפליקציות, ללא קשר לגרסה של ערכת ה-SDK שמוגדרת כיעד וללא קשר לכך שהאפליקציות מייצאות את ספקי התוכן שלהן.

כדי שאפליקציות שמטרגטות ל-Android 11 ואילך יוכלו לגשת ל-URI של התוכן, ה-intent של האפליקציה צריך להצהיר על הרשאות גישה ל-URI על ידי הגדרת אחד או שני הדגלים הבאים של ה-intent: FLAG_GRANT_READ_URI_PERMISSION ו-FLAG_GRANT_WRITE_URI_PERMISSION.

ב-Android מגרסה 11 ואילך, הרשאות הגישה למזהי ה-URI מעניקות לאפליקציה שמקבלת את ה-intent את היכולות הבאות:

  • לקרוא מהנתונים ש-URI התוכן מייצג או לכתוב אליהם, בהתאם להרשאות ה-URI הנתונות.
  • מקבלים הרשאות גישה לאפליקציה שמכילה את ספק התוכן שתואם לרשות ה-URI. יכול להיות שהאפליקציה שמכילה את ספק התוכן שונה מהאפליקציה ששולחת את הכוונה.

קטע הקוד הבא מראה איך להוסיף דגל של כוונה להרשאות URI כדי שאפליקציה אחרת שמטרגטת Android 11 ואילך תוכל להציג את הנתונים ב-URI של התוכן:

Kotlin

val shareIntent = Intent(Intent.ACTION_VIEW).apply {
    flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
    data = CONTENT_URI_TO_SHARE_WITH_OTHER_APP
}

Java

Intent shareIntent = new Intent(Intent.ACTION_VIEW);
shareIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.setData(CONTENT_URI_TO_SHARE_WITH_OTHER_APP);

חיבור לשירותים

אם האפליקציה צריכה לקיים אינטראקציה עם שירות שלא גלוי באופן אוטומטי, אפשר להצהיר על פעולת הכוונה המתאימה בתוך אלמנט <queries>. בקטעים הבאים מפורטות דוגמאות לשירותים נפוצים.

חיבור למנוע המרת טקסט לדיבור

אם האפליקציה מקיימת אינטראקציה עם מנוע של המרת טקסט לדיבור (TTS), צריך לכלול את רכיב ה-<intent> הבא כחלק מהרכיב <queries> במניפסט:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.TTS_SERVICE" />
</intent>

התחברות לשירות של זיהוי דיבור

אם האפליקציה מקיימת אינטראקציה עם שירות זיהוי דיבור, צריך לכלול את הרכיב <intent> הבא כחלק מהרכיב <queries> במניפסט:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.speech.RecognitionService" />
</intent>

חיבור לשירותי דפדפני מדיה

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

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.media.browse.MediaBrowserService" />
</intent>

לספק פונקציונליות מותאמת אישית

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

שליחת שאילתה לאפליקציות SMS

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

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.SENDTO"/>
  <data android:scheme="smsto" android:host="*" />
</intent>

יצירת גיליון שיתוף בהתאמה אישית

כשאפשר, כדאי להשתמש בחלונית שיתוף שמספקת המערכת. לחלופין, אפשר לכלול את רכיב <intent> הבא כחלק מהרכיב <queries> במניפסט:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.SEND" />
  <!-- Replace with the MIME type that your app works with, if needed. -->
  <data android:mimeType="image/jpeg" />
</intent>

תהליך היצירה של חלונית השיתוף בלוגיקה של האפליקציה, כמו הקריאה ל-queryIntentActivities(), לא השתנה בהשוואה לגרסאות Android שקדמו ל-Android 11.

הצגת פעולות מותאמות אישית לבחירת טקסט

כשמשתמשים בוחרים טקסט באפליקציה, סרגל הכלים של בחירת הטקסט מציג את קבוצת הפעולות האפשריות שאפשר לבצע בטקסט שנבחר. אם בסרגל הכלים הזה מוצגות פעולות בהתאמה אישית מאפליקציות אחרות, צריך לכלול את האלמנט <intent> כחלק מהאלמנט <queries> במניפסט:

<!-- Place inside the <queries> element. -->
<intent>
  <action android:name="android.intent.action.PROCESS_TEXT" />
  <data android:mimeType="text/plain" />
</intent>

הצגת שורות של נתונים מותאמים אישית של איש קשר

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

  1. קוראים את הקובץ contacts.xml מהאפליקציות האחרות.
  2. טוענים סמל שתואם לסוג ה-MIME המותאם אישית.

אם האפליקציה שלכם היא אפליקציית אנשי קשר, צריך לכלול את הרכיבים הבאים של <intent> כחלק מהרכיב <queries> במניפסט:

<!-- Place inside the <queries> element. -->
<!-- Lets the app read the contacts.xml file from other apps. -->
<intent>
  <action android:name="android.accounts.AccountAuthenticator" />
</intent>
<!-- Lets the app load an icon corresponding to the custom MIME type. -->
<intent>
  <action android:name="android.intent.action.VIEW" />
  <data android:scheme="content" android:host="com.android.contacts"
        android:mimeType="vnd.android.cursor.item/*" />
</intent>