קבלת נתונים מאפליקציות אחרות

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

באפליקציה שמשתמשת ב-Compose Navigation, קבלת נתונים שנשלחו על ידי אפליקציה אחרת היא תהליך בן שלושה שלבים:

  1. הצהרה על <intent-filter> במניפסט: עדיין צריך להוסיף מסנן Intent לפעילות בקובץ AndroidManifest.xml. כך מערכת ההפעלה Android יודעת שהאפליקציה יכולה לקבל פעולות ספציפיות (כמו ACTION_SEND) וסוגי MIME (כמו text/plain).

  2. מגדירים navDeepLink בתרשים הניווט של Compose: מצרפים navDeepLink שתואם לפעולה ולסוג ה-MIME ישירות ליעד ה-Composable שבו התוכן אמור להופיע. ה-NavController מיירט באופן אוטומטי את ה-intent הנכנס ומנתב את המשתמש ישירות למסך הזה.

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

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

סוגי MIME נתמכים

באופן אידיאלי, האפליקציה צריכה להיות מסוגלת לקבל את המגוון הרחב ביותר של סוגי MIME. לדוגמה, אפליקציית הודעות שמיועדת לשליחת טקסט, תמונות וסרטונים צריכה לתמוך בקבלת text/*, image/* ו-video/*. אלה כמה סוגי MIME נפוצים לשליחה ולקבלה של נתונים ב-Android.

למה הנמענים נרשמים מה שולחים
text/*
  • text/plain
  • text/rtf
  • text/html
  • text/json
image/*
  • image/jpg
  • image/png
  • image/gif
video/*
  • video/mp4
  • video/3gp
סיומות קבצים נתמכות application/pdf

אפשר לעיין במרשם הרשמי של IANA לסוגי מדיה של MIME.

יצירת יעדי שיתוף מעולים

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

קבלת נתונים באפליקציה

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

עדכון המניפסט

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

<activity android:name=".ui.MyActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
</activity>

כשאפליקציה אחרת מנסה לשתף אחד מהדברים האלה על ידי יצירת Intent והעברה שלו אל startActivity(), האפליקציה שלכם מופיעה כאפשרות בקובץ לשיתוף ב-Android או ב-intent resolver. אם המשתמש בוחר באפליקציה שלכם, הפעילות המתאימה מתחילה (.ui.MyActivity בדוגמה הקודמת). אחרי שהתוכן מתקבל, אתם צריכים לטפל בו בצורה מתאימה בקוד ובממשק המשתמש שלכם.

ב-Compose Navigation, מצרפים navDeepLink ישירות ליעד הקומפוזבילי שבו התוכן אמור להופיע. כשאפליקציה אחרת משתפת נתונים שתואמים למסנן ה-Intent, המערכת של Compose Navigation מנתבת את המשתמש ישירות ליעד הזה:

ה-navDeepLink מתאים לפעולה ולסוג ה-MIME של ה-Intent הנכנס כדי לנווט למסך היעד הנכון. אחרי שהמשתמש מגיע ליעד, ה-handler בודק את ה-intent כדי לקבוע איזה מטען ייעודי (payload) התקבל (למשל, תמונה אחת לעומת כמה תמונות) ומחלץ את הנתונים הנוספים המתאימים.

טיפול בתוכן הנכנס

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

חשוב לבדוק היטב את הנתונים הנכנסים: יכול להיות שמוגדר סוג MIME שגוי, או שהתמונה שנשלחת גדולה מדי. כדאי לעבד נתונים בינאריים או פעולות קלט/פלט כבדות (כמו פענוח של תמונות גדולות או כתיבת קבצים) באופן אסינכרוני באמצעות פונקציות Coroutine (כמו Dispatchers.IO) במקום בשרשור ה-UI הראשי.

@Composable
fun SharesheetHandler() {
    val activity = LocalActivity.current
    val intent = activity?.intent

    when (intent?.action) {
        Intent.ACTION_SEND -> {
            if (intent.type == "text/plain") {
                handleSendText(intent) // Handle text being sent
            } else if (intent.type?.startsWith("image/") == true) {
                handleSendImage(intent) // Handle single image being sent
            }
        }

        Intent.ACTION_SEND_MULTIPLE -> {
            if (intent.type?.startsWith("image/") == true) {
                handleSendMultipleImages(intent) // Handle multiple images being sent
            }
        }

        else -> {
            // Handle other intents, such as being started from the home screen
        }
    }
}

private fun handleSendText(intent: Intent) {
    intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
        // Update UI state with the shared text
    }
}

private fun handleSendImage(intent: Intent) {
    val imageUri = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)
    imageUri?.let {
        // Update UI state with the shared image
    }
}

private fun handleSendMultipleImages(intent: Intent) {
    val imageUris =
        IntentCompat.getParcelableArrayListExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)
    imageUris?.let {
        // Update UI state with the shared images
    }
}

כשמחלצים נתונים בינאריים או מזהי URI מתוספות של Intent (כמו EXTRA_STREAM), צריך להשתמש ב-IntentCompat.getParcelableExtra() או ב-IntentCompat.getParcelableArrayListExtra() מספריית הליבה של AndroidX, כפי שמוצג בפונקציות handleSendImage ו-handleSendMultipleImages שלמעלה. ב-Android 13 (רמת API‏ 33), השיטה Intent.getParcelableExtra(String) ללא פרמטרים הוצאה משימוש, ובמקומה משתמשים בשיטות למניעת שגיאות הקלדה שמקבלות את סוג המחלקה הצפוי.

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

שיתוף כתובת URL של צילום מסך

כשאתם מצלמים את המסך, אתם יכולים לשתף את צילום המסך ואת כתובת ה-URL שמשויכת אליו. כך חוויית המשתמש עשירה יותר. כשמקבלים כתובת URL, חשוב לקבל את השדה EXTRA_TEXT מה-intent, כמו בדוגמה הבאה:

IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java).let {
    // Handle the EXTRA_TEXT as well
    val extraText = intent.getCharSequenceExtra(Intent.EXTRA_TEXT)
    // Update UI state with the shared image and the EXTRA_TEXT if available
}

חשוב לוודא שהמשתמשים מזהים את האפליקציה שלכם

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

החל מ-Android 10 (רמת API‏ 29), הקובץ לשיתוף ב-Android משתמש רק בסמלים שמוגדרים במניפסט בתג application. מערכת Android מתעלמת מסמלים שמוגדרים בתגים intent-filter ו-activity.

קבלת תוכן עשיר

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

  • הדבקה מהלוח (תפריט לחיצה ארוכה)
  • הוספת מדיה ישירות מהמקלדת הווירטואלית (IME), כמו סטיקרים או קובצי GIF
  • גרירה ושחרור של תוכן מאפליקציה אחרת במצב ריבוי חלונות או מצב מסך מפוצל

בממשקי משתמש שמבוססים על תצוגה, ב-Android 12 (רמת API‏ 31) וב-AndroidX Core 1.7 יש את ה-API המאוחד OnReceiveContentListener. המאזין הזה מאחד את הטיפול בתוכן מהלוח, מהמקלדת ומהגרירה והשחרור לקריאה חוזרת (callback) אחת. הוראות מפורטות להטמעה ב-Views מופיעות במאמר קבלת תוכן עשיר.

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