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

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

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

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

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

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

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

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

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

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

ה-method‏ 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() ומעבירים Intent של אינטרנט כארגומנט, הרשימה שמוחזרת כוללת במקרים מסוימים את אפליקציות הדפדפן הזמינות. הרשימה לא כוללת אפליקציות דפדפן אם המשתמש הגדיר את כתובת ה-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() באמצעות Intent שמגדיר את דגל ה-Intent‏ FLAG_ACTIVITY_REQUIRE_NON_BROWSER. אם המערכת מחזירה ActivityNotFoundException, האפליקציה יכולה לפתוח את כתובת ה-URL בכרטיסייה מותאמת אישית.

אם Intent כולל את הדגל הזה, קריאה ל-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 שמגדיר את הדגל של ה-Intent FLAG_ACTIVITY_REQUIRE_DEFAULT.

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

אם Intent כולל גם את הדגל הזה וגם את הדגל 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 שכולל את פעולת ה-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() עם ה-intent.

מתן גישה ל-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. האפליקציה שמכילה את הספק לניהול גישה עשויה להיות שונה מהאפליקציה ששולחת את ה-Intent.

קטע הקוד הבא מדגים איך להוסיף דגל Intent של הרשאות 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);

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

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

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

אם האפליקציה שלכם מקיימת אינטראקציה עם מנוע המרת טקסט לדיבור (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>

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

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

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

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