משתמשים אוהבים תמונות, סרטונים ותוכן אחר שמאפשר להם להביע את עצמם, אבל לא תמיד קל להוסיף את התוכן הזה לאפליקציות ולהעביר אותו. כדי לפשט את התהליך של קבלת תוכן עשיר באפליקציות, ב-Android 12 (רמת API 31) הושק API מאוחד שמאפשר לאפליקציה לקבל תוכן מכל מקור: לוח, מקלדת או גרירה.
אפשר לצרף ממשק, כמו OnReceiveContentListener
, לרכיבי ממשק משתמש ולקבל קריאה חוזרת (callback) כשתוכן מוכנס דרך מנגנון כלשהו. הקריאה החוזרת הופכת למקום היחיד שבו הקוד יכול לטפל בקבלת כל התוכן, מטקסט רגיל ומעוצב ועד לתגי עיצוב, תמונות, סרטונים, קובצי אודיו ועוד.
כדי לשמור על תאימות לאחור עם גרסאות קודמות של Android, ממשק ה-API הזה זמין גם ב-AndroidX, החל מCore 1.7 ומ-Appcompat 1.4. מומלץ להשתמש בו כשמטמיעים את הפונקציונליות הזו.
סקירה כללית
בממשקי API קיימים אחרים, לכל מנגנון בממשק המשתמש – כמו תפריט הלחיצה הארוכה או הגרירה – יש API משלו. כלומר, צריך לבצע שילוב עם כל API בנפרד ולהוסיף קוד דומה לכל מנגנון שמכניס תוכן:
ממשק ה-API OnReceiveContentListener
מאחד את נתיבי הקוד השונים האלה על ידי יצירת API יחיד להטמעה, כך שתוכלו להתמקד בלוגי הספציפי לאפליקציה שלכם ולתת לפלטפורמה לטפל בשאר:
הגישה הזו גם אומרת שכאשר מתווספות לפלטפורמה דרכים חדשות להוספת תוכן, לא צריך לבצע שינויים נוספים בקוד כדי להפעיל תמיכה באפליקציה. ואם האפליקציה צריכה להטמיע התאמה אישית מלאה לתרחיש שימוש מסוים, עדיין אפשר להשתמש בממשקי ה-API הקיימים, שממשיכים לפעול באותו אופן.
הטמעה
ה-API הוא ממשק listener עם method אחת, OnReceiveContentListener
.
כדי לתמוך בגרסאות ישנות יותר של פלטפורמת Android, מומלץ להשתמש בממשק התואם OnReceiveContentListener
בספריית AndroidX Core.
כדי להשתמש ב-API, צריך להטמיע את ה-listener על ידי ציון סוגי התוכן שהאפליקציה יכולה לטפל בהם:
Kotlin
object MyReceiver : OnReceiveContentListener { val MIME_TYPES = arrayOf("image/*", "video/*") // ... override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? { TODO("Not yet implemented") } }
Java
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; // ... }
אחרי שמציינים את כל סוגי ה-MIME של התוכן שהאפליקציה תומכת בהם, מטמיעים את שאר רכיבי ה-listener:
Kotlin
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/*") } }
Java
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; } }
אם האפליקציה שלכם כבר תומכת בשיתוף באמצעות Intents, תוכלו להשתמש מחדש בלוגיקה הספציפית לאפליקציה לטיפול ב-URI של תוכן. להחזיר את כל הנתונים שנותרו כדי להעביר את הטיפול בהם לפלטפורמה.
אחרי שמטמיעים את ה-listener, מגדירים אותו ברכיבי ממשק המשתמש המתאימים באפליקציה:
Kotlin
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()) } }
Java
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
שמתקבל על ידי רכיב ה-listener.
תצוגות מותאמות אישית
אם האפליקציה משתמשת במחלקת משנה מותאמת אישית של View
, חשוב לוודא שלא נעקף.OnReceiveContentListener
אם המחלקה View
מחליפה את השיטה onCreateInputConnection
, צריך להשתמש ב-Jetpack API InputConnectionCompat.createWrapper
כדי להגדיר את InputConnection
.
אם המחלקה View
מבטלת את השיטה onTextContextMenuItem
, צריך להעביר את הפריט בתפריט אל super כשהוא R.id.paste
או R.id.pasteAsPlainText
.
השוואה ל-API של תמונת המקלדת
אפשר לחשוב על OnReceiveContentListener
API כגרסה הבאה של keyboard image API הקיים. ממשק ה-API המאוחד הזה תומך בפונקציונליות של ממשק ה-API של תמונת המקלדת, וגם בכמה תכונות נוספות. התאימות של המכשיר והתכונה משתנה בהתאם לשימוש בספריית Jetpack או בממשקי ה-API המקוריים מ-Android SDK.
פעולה או תכונה | נתמך על ידי API של תמונת מקלדת | נתמך על ידי Unified API |
---|---|---|
הוספה מהמקלדת | כן (רמת API 13 ומעלה) | כן (רמת API 13 ומעלה) |
הוספה באמצעות הדבקה מהתפריט של לחיצה ארוכה | לא | כן |
הוספה באמצעות גרירה ושחרור | לא | כן (רמת API 24 ומעלה) |
פעולה או תכונה | נתמך על ידי API של תמונת מקלדת | נתמך על ידי Unified API |
---|---|---|
הוספה מהמקלדת | כן (רמת API 25 ומעלה) | כן (Android מגרסה 12 ואילך) |
הוספה באמצעות הדבקה מהתפריט של לחיצה ארוכה | לא | |
הוספה באמצעות גרירה ושחרור | לא |