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

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

משתמשים אוהבים תמונות, סרטונים ותוכן נוסף שמאפשר להם להביע את עצמם, אבל לא תמיד קל להוסיף תוכן כזה לאפליקציות ולהעביר אותו. כדי להקל על אפליקציות מקבלים תוכן עשיר, גרסת Android 12 (רמת API 31) מציגה ממשק API מאוחד מאפשר לאפליקציה לקבל תוכן מכל מקור: לוח, מקלדת או גרירה.

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

לצורך תאימות לאחור עם גרסאות Android קודמות, ה-API הזה זמין ב-AndroidX, החל מ- Core 1.7 ו- Appcompat 1.4, שבו מומלץ להשתמש כאשר מטמיעים את הפונקציונליות הזו.

סקירה כללית

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

תמונה שמציגה את הפעולות השונות ואת ממשק ה-API הרלוונטי להטמעה
איור 2. בעבר, אפליקציות הטמיעו ממשק API שונה לכל ממשק משתמש מנגנון להוספת תוכן.

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

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

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

הטמעה

ה-API הוא ממשק האזנה עם שיטה אחת, OnReceiveContentListener כדי לתמוך בגרסאות ישנות של פלטפורמת Android, מומלץ להשתמש תואם OnReceiveContentListener בספריית AndroidX Core.

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

KotlinJava
object MyReceiver : OnReceiveContentListener {
    val MIME_TYPES = arrayOf("image/*", "video/*")
    
    // ...
    
    override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
        TODO("Not yet implemented")
    }
}
public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
     // ...
}

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

KotlinJava
class MyReceiver : OnReceiveContentListener {
    override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat {
        val split = contentInfo.partition { item: ClipData.Item -> item.uri != null }
        val uriContent = split.first
        val remaining = split.second
        if (uriContent != null) {
            // App-specific logic to handle the URI(s) in uriContent.
        }
        // Return anything that your app didn't handle. This preserves the
        // default platform behavior for text and anything else that you aren't
        // implementing custom handling for.
        return remaining
    }

    companion object {
        val MIME_TYPES = arrayOf("image/*", "video/*")
    }
}
 public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};

     @Override
     public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) {
         Pair<ContentInfoCompat, ContentInfoCompat> split = contentInfo.partition(
                 item -> item.getUri() != null);
         ContentInfo uriContent = split.first;
         ContentInfo remaining = split.second;
         if (uriContent != null) {
             // App-specific logic to handle the URI(s) in uriContent.
         }
         // Return anything that your app didn't handle. This preserves the
         // default platform behavior for text and anything else that you aren't
         // implementing custom handling for.
         return remaining;
     }
 }

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

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

KotlinJava
class MyActivity : Activity() {
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        val myInput = findViewById(R.id.my_input)
        ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver())
    }
}
public class MyActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         // ...

         AppCompatEditText myInput = findViewById(R.id.my_input);
         ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver());
     }
}

הרשאות URI

המערכת מעניקה ומבטלת באופן אוטומטי הרשאות קריאה לכל מזהי URI של תוכן בתוכן הייעודי (payload) שמוענק ל-OnReceiveContentListener.

בדרך כלל, האפליקציה מעבדת מזהי URI של תוכן בשירות או בפעילות. עבור לעיבוד ממושך, צריך להשתמש WorkManager. כאשר מטמיעים זאת, להרחיב את ההרשאות לשירות או לפעילות היעד על ידי העברת תוכן באמצעות Intent.setClipData ולהגדיר את הדגל FLAG_GRANT_READ_URI_PERMISSION.

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

תצוגות מותאמות אישית

אם באפליקציה שלך נעשה שימוש במחלקה משנית מותאמת אישית של View, צריך לוודא לא ניתן לעקוף את OnReceiveContentListener.

אם הכיתה View מבטלת את onCreateInputConnection צריך להשתמש ב-Jetpack API InputConnectionCompat.createWrapper כדי להגדיר את InputConnection.

אם בכיתה View מתבצעת החלפה של השיטה onTextContextMenuItem, מעבירים את הטיפול ל-super כשפריט התפריט הוא R.id.paste או R.id.pasteAsPlainText.

השוואה ל-Keyboard Image API

אפשר להתייחס ל-API OnReceiveContentListener כגרסה הבאה של ממשק ה-API הקיים לתמונות של מקלדת. הגרסה המאוחדת ה-API תומך בפונקציונליות של ממשק ה-API של תמונת המקלדת תכונות נוספות. התאימות של מכשירים ותכונות משתנה בהתאם בין אם אתם משתמשים בספריית Jetpack או בממשקי ה-API המקוריים מ-Android SDK.

טבלה 1. תכונות נתמכות ורמות API ב-Jetpack
פעולה או תכונה נתמך על ידי ממשק ה-API של תמונת המקלדת תמיכה באמצעות API מאוחד
הוספה מהמקלדת כן (רמת API 13 ואילך) כן (רמת API 13 ומעלה)
הוספה באמצעות הדבקה מהתפריט של הלחיצה הארוכה לא כן
הוספה באמצעות גרירה ושחרור לא כן (רמת API 24 ואילך)
טבלה 2. התכונות והרמות הנתמכות של ממשקי API מקומיים.
פעולה או תכונה נתמך על ידי ממשק ה-API של תמונת המקלדת תמיכה באמצעות API מאוחד
הוספה מהמקלדת כן (רמת API 25 ומעלה) כן (Android מגרסה 12 ואילך)
הוספה באמצעות הדבקה מהתפריט של הלחיצה הארוכה לא
הוספה באמצעות גרירה ושחרור לא