העתקה והדבקה

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

מאחר שחלק מה-framework משתמש בספקי תוכן, המסמך הזה מניח שיש לכם היכרות מסוימת עם ממשק ה-API של Android Content Provider, שמתואר ספקי תוכן.

המשתמשים מצפים לקבל משוב כשהם מעתיקים תוכן ללוח, כך שבנוסף ל-framework שמפעילה העתקה והדבקה, מערכת Android מציגה למשתמשים ממשק משתמש שמוגדר כברירת מחדל כשמעתיקים את Android 13 (רמת API 33) גבוהה יותר. בגלל התכונה הזו, יש סיכון לקבל התראה כפולה. אפשר לקבל מידע נוסף על את רצף הקצה הזה איך נמנעים מכפילויות בתזכורות .

אנימציה שמציגה הודעה על לוח העריכה של Android 13
איור 1. ממשק משתמש שמוצג כשתוכן נכנס ללוח ב-Android 13 ומעלה.

שליחת משוב למשתמשים באופן ידני בזמן העתקה ב-Android מגרסה 12L (API ברמה 32) ומטה. צפייה המלצות בנושא במסמך זה.

מסגרת הלוח

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

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

הלוח יכול להחזיק רק אובייקט קליפ אחד בכל פעם. כשאפליקציה מציבה אובייקט קליפ אובייקט הקליפ הקודם ייעלם.

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

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

שיעורים של לוח אינטראקטיבי

בקטע הזה מתוארות הכיתות שבהן נעשה שימוש במסגרת של הלוח.

מנהל הלוח

הלוח של מערכת Android מיוצג על ידי הפרמטר הגלובלי כיתה אחת (ClipboardManager). אין ליצור את המחלקה הזו ישירות. במקום זאת, אפשר לקבל הפניה אליו על ידי הפעלה getSystemService(CLIPBOARD_SERVICE)

ClipData, ClipData.Item ו-ClipDescription

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

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

אובייקט ClipData.Item מכיל את נתוני הטקסט, ה-URI או ה-Intent:

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

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

שיטות הנוחות של ClipData

המחלקה ClipData מספקת שיטות נוחות סטטיות ליצירת אובייקט ClipData עם אובייקט ClipData.Item אחד ויעד פשוט אובייקט ClipDescription:

newPlainText(label, text)
מוחזר אובייקט ClipData שאובייקט ClipData.Item היחיד שלו מכיל מחרוזת טקסט. התווית של האובייקט ClipDescription מוגדרת כך label. סוג ה-MIME היחיד ב-ClipDescription הוא MIMETYPE_TEXT_PLAIN.

אפשר להשתמש ב-newPlainText() כדי ליצור קליפ ממחרוזת טקסט.

newUri(resolver, label, URI)
מוחזר אובייקט ClipData שאובייקט ClipData.Item היחיד שלו מכיל URI. התווית של האובייקט ClipDescription מוגדרת כך label. אם ה-URI הוא URI של תוכן – כלומר, Uri.getScheme() מחזירה content: - השיטה משתמשת באופרטור ContentResolver שסופק ב-resolver כדי לאחזר את סוגי ה-MIME הזמינים ספק תוכן. לאחר מכן הם נשמרים בClipDescription. עבור URI שאינו URI של content:, ה-method מגדיר את סוג ה-MIME MIMETYPE_TEXT_URILIST.

אפשר להשתמש ב-newUri() כדי ליצור קליפ מ-URI, במיוחד URI של content:.

newIntent(label, intent)
מוחזר אובייקט ClipData שאובייקט ClipData.Item היחיד שלו מכיל Intent. התווית של האובייקט ClipDescription מוגדרת כך label. סוג ה-MIME מוגדר להיות MIMETYPE_TEXT_INTENT

אפשר להשתמש ב-newIntent() כדי ליצור קליפ מאובייקט Intent.

אילוץ הנתונים שבלוח העריכה לטקסט

גם אם האפליקציה מטפלת רק בטקסט, אפשר להעתיק מהלוח נתונים שאינם טקסט באמצעות להמיר אותו באמצעות ClipData.Item.coerceToText() .

השיטה הזו ממירה את הנתונים בקובץ ClipData.Item לטקסט ומחזירה CharSequence. הערך ש-ClipData.Item.coerceToText() מחזיר מבוסס בצורת הנתונים ב-ClipData.Item:

טקסט
אם ClipData.Item הוא טקסט. כלומר, אם getText() אינה null—coerceToText() מחזירה את הטקסט.
URI
אם ClipData.Item הוא URI – כלומר, getUri() אינו null — coerceToText() מנסה להשתמש בו כ-URI של תוכן.
  • אם ה-URI הוא URI של תוכן והספק יכול להחזיר זרם טקסט, הפונקציה coerceToText() מחזירה זרם טקסט.
  • אם ה-URI הוא URI של תוכן אבל הספק לא מציע זרם טקסט, coerceToText() מחזירה ייצוג של ה-URI. הייצוג הוא זהה לערך שהוחזר על ידי Uri.toString()
  • אם ה-URI אינו URI של תוכן, coerceToText() מחזיר ייצוג של ב-URI. הייצוג זהה לייצוג שהוחזר על ידי Uri.toString()
כוונה
אם ClipData.Item הוא Intent – כלומר, אם getIntent() שאינו null — מערכת coerceToText() ממירה אותו ל-URI של Intent ומחזירה אותו. הייצוג זהה לייצוג שהוחזר על ידי Intent.toUri(URI_INTENT_SCHEME)

מסגרת הלוח מסוכמת בתרשים 2. כדי להעתיק נתונים, אפליקציה מציבה אובייקט ClipData בלוח הגלובלי ClipboardManager. ClipData מכיל אובייקט ClipData.Item אחד או יותר ואובייקט אחד אובייקט ClipDescription. כדי להדביק נתונים, אפליקציה מקבלת את ClipData, מקבל את סוג ה-MIME שלו מה-ClipDescription, ומאחזר את הנתונים ClipData.Item או מספק התוכן שהפנו אליו ClipData.Item.

תמונה שמוצג בה תרשים בלוקים של מסגרת ההעתקה וההדבקה
איור 2. מסגרת הלוח של Android.

העתקה ללוח

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

  1. אם מעתיקים נתונים באמצעות URI של תוכן, צריך להגדיר ספק תוכן.
  2. משיגים את לוח המערכת:

    Kotlin

    when(menuItem.itemId) {
        ...
        R.id.menu_copy -> { // if the user selects copy
            // Gets a handle to the clipboard service.
            val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
        }
    }
    

    Java

    ...
    // If the user selects copy.
    case R.id.menu_copy:
    
    // Gets a handle to the clipboard service.
    ClipboardManager clipboard = (ClipboardManager)
            getSystemService(Context.CLIPBOARD_SERVICE);
    
  3. מעתיקים את הנתונים לאובייקט ClipData חדש:

    • לטקסט

      Kotlin

      // Creates a new text clip to put on the clipboard.
      val clip: ClipData = ClipData.newPlainText("simple text", "Hello, World!")
      

      Java

      // Creates a new text clip to put on the clipboard.
      ClipData clip = ClipData.newPlainText("simple text", "Hello, World!");
      
    • ל-URI

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

      Kotlin

      // Creates a Uri using a base Uri and a record ID based on the contact's last
      // name. Declares the base URI string.
      const val CONTACTS = "content://com.example.contacts"
      
      // Declares a path string for URIs, used to copy data.
      const val COPY_PATH = "/copy"
      
      // Declares the Uri to paste to the clipboard.
      val copyUri: Uri = Uri.parse("$CONTACTS$COPY_PATH/$lastName")
      ...
      // Creates a new URI clip object. The system uses the anonymous
      // getContentResolver() object to get MIME types from provider. The clip object's
      // label is "URI", and its data is the Uri previously created.
      val clip: ClipData = ClipData.newUri(contentResolver, "URI", copyUri)
      

      Java

      // Creates a Uri using a base Uri and a record ID based on the contact's last
      // name. Declares the base URI string.
      private static final String CONTACTS = "content://com.example.contacts";
      
      // Declares a path string for URIs, used to copy data.
      private static final String COPY_PATH = "/copy";
      
      // Declares the Uri to paste to the clipboard.
      Uri copyUri = Uri.parse(CONTACTS + COPY_PATH + "/" + lastName);
      ...
      // Creates a new URI clip object. The system uses the anonymous
      // getContentResolver() object to get MIME types from provider. The clip object's
      // label is "URI", and its data is the Uri previously created.
      ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri);
      
    • בכוונת רכישה

      קטע הקוד הזה בונה Intent לאפליקציה ולאחר מכן מוסיף באובייקט הקליפ:

      Kotlin

      // Creates the Intent.
      val appIntent = Intent(this, com.example.demo.myapplication::class.java)
      ...
      // Creates a clip object with the Intent in it. Its label is "Intent"
      // and its data is the Intent object created previously.
      val clip: ClipData = ClipData.newIntent("Intent", appIntent)
      

      Java

      // Creates the Intent.
      Intent appIntent = new Intent(this, com.example.demo.myapplication.class);
      ...
      // Creates a clip object with the Intent in it. Its label is "Intent"
      // and its data is the Intent object created previously.
      ClipData clip = ClipData.newIntent("Intent", appIntent);
      
  4. מוסיפים את אובייקט הקליפ החדש ללוח:

    Kotlin

    // Set the clipboard's primary clip.
    clipboard.setPrimaryClip(clip)
    

    Java

    // Set the clipboard's primary clip.
    clipboard.setPrimaryClip(clip);
    

שליחת משוב בזמן העתקה ללוח

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

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

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

אנימציה שמציגה הודעה על לוח העריכה של Android 13
איור 3. ממשק משתמש שמוצג כשתוכן נכנס ללוח ב-Android 13 ומעלה.

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

איך נמנעים מכפילויות בתזכורות

ב-Android מגרסה 12L (רמת API 32) ומטה, מומלץ להתריע למשתמשים כשהם מעתיקים בהצלחה באמצעות שליחת משוב ויזואלי מתוך האפליקציה, באמצעות ווידג'ט כמו Toast או Snackbar, אחרי ההעתקה.

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

סרגל אינטראקטיבי לפרסום אחרי עותק בתוך האפליקציה.
איור 4. אם מציגים סרגל אינטראקטיבי לאישור העתקה ב-Android 13, המשתמש רואה הודעות כפולות.
פרסום הודעה הודעה אחרי עותק של עותק בתוך האפליקציה.
איור 5. אם מוצג הודעה על אישור העתקה ב-Android 13: המשתמש רואה הודעות כפולות.

לדוגמה:

fun textCopyThenPost(textCopied:String) {
    val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
    // When setting the clipboard text.
    clipboardManager.setPrimaryClip(ClipData.newPlainText   ("", textCopied))
    // Only show a toast for Android 12 and lower.
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2)
        Toast.makeText(context, Copied, Toast.LENGTH_SHORT).show()
}

הוספת תוכן רגיש ללוח

אם האפליקציה מאפשרת למשתמשים להעתיק תוכן רגיש ללוח, כמו סיסמאות או קרדיט פרטי הכרטיס, עליך להוסיף דגל ל-ClipDescription בClipData לפני קריאה אל ClipboardManager.setPrimaryClip(). הוספת הסימון הזה מונעת פרסום של תוכן רגיש כדי שהתוכן לא יופיע באישור החזותי של תוכן שהועתק ב-Android 13 ואילך.

תצוגה מקדימה של הטקסט שהועתק בלי לסמן תוכן רגיש
איור 6. תצוגה מקדימה של הטקסט שהועתק בלי סימון של תוכן רגיש.
תצוגה מקדימה של הטקסט שהועתק מסמן תוכן רגיש.
איור 7. תצוגה מקדימה של טקסט שהועתק עם סימון של תוכן רגיש.

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

// If your app is compiled with the API level 33 SDK or higher.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
    }
}

// If your app is compiled with a lower SDK.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean("android.content.extra.IS_SENSITIVE", true)
    }
}

הדבקה מהלוח

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

הדבקת טקסט פשוט

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

  1. מקבלים את האובייקט ClipboardManager הגלובלי באמצעות getSystemService(CLIPBOARD_SERVICE). כמו כן, צריך להצהיר על משתנה גלובלי שמכיל הטקסט שהודבק:

    Kotlin

    var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    var pasteData: String = ""
    

    Java

    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    String pasteData = "";
    
  2. מחליטים אם צריך להפעיל או להשבית את האפשרות 'הדבקה' באפשרות הנוכחית, פעילות. צריך לוודא שהלוח מכיל קליפ ושאפשר לטפל בסוג הנתונים שהייצוג שלו הוא הקליפ:

    Kotlin

    // Gets the ID of the "paste" menu item.
    val pasteItem: MenuItem = menu.findItem(R.id.menu_paste)
    
    // If the clipboard doesn't contain data, disable the paste menu item.
    // If it does contain data, decide whether you can handle the data.
    pasteItem.isEnabled = when {
        !clipboard.hasPrimaryClip() -> {
            false
        }
        !(clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN)) -> {
            // Disables the paste menu item, since the clipboard has data but it
            // isn't plain text.
            false
        }
        else -> {
            // Enables the paste menu item, since the clipboard contains plain text.
            true
        }
    }
    

    Java

    // Gets the ID of the "paste" menu item.
    MenuItem pasteItem = menu.findItem(R.id.menu_paste);
    
    // If the clipboard doesn't contain data, disable the paste menu item.
    // If it does contain data, decide whether you can handle the data.
    if (!(clipboard.hasPrimaryClip())) {
    
        pasteItem.setEnabled(false);
    
    } else if (!(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN))) {
    
        // Disables the paste menu item, since the clipboard has data but
        // it isn't plain text.
        pasteItem.setEnabled(false);
    } else {
    
        // Enables the paste menu item, since the clipboard contains plain text.
        pasteItem.setEnabled(true);
    }
    
  3. מעתיקים את הנתונים מהלוח. ניתן להגיע לנקודה הזו בקוד רק אם 'הדבקה' האפשרות בתפריט מופעלת, כך שניתן להניח שהלוח מכיל טקסט. עדיין לא ידוע לך אם העמודה מכילה מחרוזת טקסט או URI שמפנה לטקסט פשוט. קטע הקוד הבא בודק את הבעיה, אבל הוא מציג את הקוד רק לטיפול בטקסט פשוט:

    Kotlin

    when (menuItem.itemId) {
        ...
        R.id.menu_paste -> {    // Responds to the user selecting "paste".
            // Examines the item on the clipboard. If getText() doesn't return null,
            // the clip item contains the text. Assumes that this application can only
            // handle one item at a time.
            val item = clipboard.primaryClip.getItemAt(0)
    
            // Gets the clipboard as text.
            pasteData = item.text
    
            return if (pasteData != null) {
                // If the string contains data, then the paste operation is done.
                true
            } else {
                // The clipboard doesn't contain text. If it contains a URI,
                // attempts to get data from it.
                val pasteUri: Uri? = item.uri
    
                if (pasteUri != null) {
                    // If the URI contains something, try to get text from it.
    
                    // Calls a routine to resolve the URI and get data from it.
                    // This routine isn't presented here.
                    pasteData = resolveUri(pasteUri)
                    true
                } else {
    
                    // Something is wrong. The MIME type was plain text, but the
                    // clipboard doesn't contain text or a Uri. Report an error.
                    Log.e(TAG,"Clipboard contains an invalid data type")
                    false
                }
            }
        }
    }
    

    Java

    // Responds to the user selecting "paste".
    case R.id.menu_paste:
    
    // Examines the item on the clipboard. If getText() does not return null,
    // the clip item contains the text. Assumes that this application can only
    // handle one item at a time.
     ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);
    
    // Gets the clipboard as text.
    pasteData = item.getText();
    
    // If the string contains data, then the paste operation is done.
    if (pasteData != null) {
        return true;
    
    // The clipboard doesn't contain text. If it contains a URI, attempts to get
    // data from it.
    } else {
        Uri pasteUri = item.getUri();
    
        // If the URI contains something, try to get text from it.
        if (pasteUri != null) {
    
            // Calls a routine to resolve the URI and get data from it.
            // This routine isn't presented here.
            pasteData = resolveUri(Uri);
            return true;
        } else {
    
            // Something is wrong. The MIME type is plain text, but the
            // clipboard doesn't contain text or a Uri. Report an error.
            Log.e(TAG, "Clipboard contains an invalid data type");
            return false;
        }
    }
    

הדבקת נתונים מ-URI של תוכן

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

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

  1. הצהרה על משתנה גלובלי שיכיל סוג MIME:

    Kotlin

    // Declares a MIME type constant to match against the MIME types offered
    // by the provider.
    const val MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
    

    Java

    // Declares a MIME type constant to match against the MIME types offered by
    // the provider.
    public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
    
  2. אפשר לקבל את הלוח הגלובלי. צריך גם להוריד מקודד תוכן כדי לגשת לתוכן ספק:

    Kotlin

    // Gets a handle to the Clipboard Manager.
    val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    
    // Gets a content resolver instance.
    val cr = contentResolver
    

    Java

    // Gets a handle to the Clipboard Manager.
    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    
    // Gets a content resolver instance.
    ContentResolver cr = getContentResolver();
    
  3. מקבלים את הקליפ הראשי מהלוח ומקבלים את התוכן שלו כ-URI:

    Kotlin

    // Gets the clipboard data from the clipboard.
    val clip: ClipData? = clipboard.primaryClip
    
    clip?.run {
    
        // Gets the first item from the clipboard data.
        val item: ClipData.Item = getItemAt(0)
    
        // Tries to get the item's contents as a URI.
        val pasteUri: Uri? = item.uri
    

    Java

    // Gets the clipboard data from the clipboard.
    ClipData clip = clipboard.getPrimaryClip();
    
    if (clip != null) {
    
        // Gets the first item from the clipboard data.
        ClipData.Item item = clip.getItemAt(0);
    
        // Tries to get the item's contents as a URI.
        Uri pasteUri = item.getUri();
    
  4. בדוק אם ה-URI הוא URI של תוכן באמצעות קריאה getType(Uri) השיטה הזו מחזירה null אם Uri לא מפנה לספק תוכן תקין.

    Kotlin

        // If the clipboard contains a URI reference...
        pasteUri?.let {
    
            // ...is this a content URI?
            val uriMimeType: String? = cr.getType(it)
    

    Java

        // If the clipboard contains a URI reference...
        if (pasteUri != null) {
    
            // ...is this a content URI?
            String uriMimeType = cr.getType(pasteUri);
    
  5. בודקים אם ספק התוכן תומך בסוג MIME שהאפליקציה מבינה. אם המיקום כן, להתקשר ContentResolver.query() כדי לקבל את הנתונים. הערך המוחזר הוא Cursor

    Kotlin

            // If the return value isn't null, the Uri is a content Uri.
            uriMimeType?.takeIf {
    
                // Does the content provider offer a MIME type that the current
                // application can use?
                it == MIME_TYPE_CONTACT
            }?.apply {
    
                // Get the data from the content provider.
                cr.query(pasteUri, null, null, null, null)?.use { pasteCursor ->
    
                    // If the Cursor contains data, move to the first record.
                    if (pasteCursor.moveToFirst()) {
    
                        // Get the data from the Cursor here.
                        // The code varies according to the format of the data model.
                    }
    
                    // Kotlin `use` automatically closes the Cursor.
                }
            }
        }
    }
    

    Java

            // If the return value isn't null, the Uri is a content Uri.
            if (uriMimeType != null) {
    
                // Does the content provider offer a MIME type that the current
                // application can use?
                if (uriMimeType.equals(MIME_TYPE_CONTACT)) {
    
                    // Get the data from the content provider.
                    Cursor pasteCursor = cr.query(uri, null, null, null, null);
    
                    // If the Cursor contains data, move to the first record.
                    if (pasteCursor != null) {
                        if (pasteCursor.moveToFirst()) {
    
                        // Get the data from the Cursor here.
                        // The code varies according to the format of the data model.
                        }
                    }
    
                    // Close the Cursor.
                    pasteCursor.close();
                 }
             }
         }
    }
    

הדבקת Intent

כדי להדביק Intent, קודם צריך להשיג את הלוח הגלובלי. בדיקת האובייקט ClipData.Item כדי לבדוק אם הוא מכיל Intent. לאחר מכן, צריך להתקשר אל getIntent() כדי להעתיק את בכוונה טובה, לאחסון שלכם. קטע הקוד הבא מדגים את זה:

Kotlin

// Gets a handle to the Clipboard Manager.
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager

// Checks whether the clip item contains an Intent by testing whether
// getIntent() returns null.
val pasteIntent: Intent? = clipboard.primaryClip?.getItemAt(0)?.intent

if (pasteIntent != null) {

    // Handle the Intent.

} else {

    // Ignore the clipboard, or issue an error if
    // you expect an Intent to be on the clipboard.
}

Java

// Gets a handle to the Clipboard Manager.
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);

// Checks whether the clip item contains an Intent, by testing whether
// getIntent() returns null.
Intent pasteIntent = clipboard.getPrimaryClip().getItemAt(0).getIntent();

if (pasteIntent != null) {

    // Handle the Intent.

} else {

    // Ignore the clipboard, or issue an error if
    // you expect an Intent to be on the clipboard.
}

התראת מערכת שמוצגת כשהאפליקציה ניגשת לנתונים בלוח העריכה

ב-Android מגרסה 12 (רמת API 31) ואילך, בדרך כלל המערכת מציגה הודעת טוסט כשהאפליקציה שיחות getPrimaryClip() הטקסט בתוך ההודעה מכיל את הפורמט הבא:

APP pasted from your clipboard

המערכת לא מציגה הודעת עדכון אם האפליקציה מבצעת אחת מהפעולות הבאות:

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

שימוש בספקי תוכן כדי להעתיק נתונים מורכבים

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

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

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

קידוד מזהה ב-URI

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

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

"content://com.example.contacts"

אם רוצים לקודד שם ב-URI הזה, צריך להשתמש בקטע הקוד הבא:

Kotlin

val uriString = "content://com.example.contacts/Smith"

// uriString now contains content://com.example.contacts/Smith.

// Generates a uri object from the string representation.
val copyUri = Uri.parse(uriString)

Java

String uriString = "content://com.example.contacts" + "/" + "Smith";

// uriString now contains content://com.example.contacts/Smith.

// Generates a uri object from the string representation.
Uri copyUri = Uri.parse(uriString);

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

"content://com.example.contacts/people"
"content://com.example.contacts/people/detail"
"content://com.example.contacts/people/images"

אפשר להוסיף נתיב אחר להעתקת מזהי URI:

"content://com.example.contacts/copying"

לאחר מכן תוכלו לזהות "עותק" URI לפי התאמה לדפוסים ולטפל בו עם קוד ספציפיים להעתקה ולהדבקה.

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

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

העתקת מבני נתונים

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

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

בספק התוכן, מבטלים לפחות את השיטות הבאות:

query()
הדבקת אפליקציות מניחה שהן יכולות לקבל את הנתונים שלך באמצעות השיטה הזו עם ה-URI שאתה לשים על הלוח. כדי לתמוך בהעתקה, שיטה זו תזהה מזהי URI שמכילים "העתקה" נתיב. לאחר מכן האפליקציה שלך תוכל ליצור "עותק" URI להוספה הלוח, שמכיל את נתיב ההעתקה ומצביע אל הרשומה המדויקת שברצונך להעתיק.
getType()
השיטה הזו חייבת להחזיר את סוגי ה-MIME של הנתונים שאתם מתכוונים להעתיק. השיטה newUri() קוראת לפונקציה getType() כדי להעביר את סוגי ה-MIME אל ClipData החדש לאובייקט.

סוגי MIME לנתונים מורכבים מתוארים ספקי תוכן.

אתם לא צריכים להשתמש באף אחת מהשיטות האחרות של ספקי התוכן, כמו insert() או update(). אפליקציה להדבקה צריכה לקבל רק את סוגי ה-MIME הנתמכים ולהעתיק נתונים מהספק. אם כבר השתמשתם בשיטות האלה, הן לא יפריעו לפעולות ההעתקה.

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

  1. בקבועים הגלובליים של האפליקציה, הצהירו על מחרוזת URI בסיסית ונתיב מזהה מחרוזות URI שמשמשות להעתקת נתונים. צריך להצהיר על סוג MIME של התוכן המועתק .

    Kotlin

    // Declares the base URI string.
    private const val CONTACTS = "content://com.example.contacts"
    
    // Declares a path string for URIs that you use to copy data.
    private const val COPY_PATH = "/copy"
    
    // Declares a MIME type for the copied data.
    const val MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
    

    Java

    // Declares the base URI string.
    private static final String CONTACTS = "content://com.example.contacts";
    
    // Declares a path string for URIs that you use to copy data.
    private static final String COPY_PATH = "/copy";
    
    // Declares a MIME type for the copied data.
    public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
    
  2. בפעילות שהמשתמשים מעתיקים ממנה נתונים, מגדירים את הקוד כדי להעתיק נתונים ללוח. בתגובה לבקשת העתקה, שימו את ה-URI בלוח.

    Kotlin

    class MyCopyActivity : Activity() {
        ...
    when(item.itemId) {
        R.id.menu_copy -> { // The user has selected a name and is requesting a copy.
            // Appends the last name to the base URI.
            // The name is stored in "lastName".
            uriString = "$CONTACTS$COPY_PATH/$lastName"
    
            // Parses the string into a URI.
            val copyUri: Uri? = Uri.parse(uriString)
    
            // Gets a handle to the clipboard service.
            val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    
            val clip: ClipData = ClipData.newUri(contentResolver, "URI", copyUri)
    
            // Sets the clipboard's primary clip.
            clipboard.setPrimaryClip(clip)
        }
    }
    

    Java

    public class MyCopyActivity extends Activity {
        ...
    // The user has selected a name and is requesting a copy.
    case R.id.menu_copy:
    
        // Appends the last name to the base URI.
        // The name is stored in "lastName".
        uriString = CONTACTS + COPY_PATH + "/" + lastName;
    
        // Parses the string into a URI.
        Uri copyUri = Uri.parse(uriString);
    
        // Gets a handle to the clipboard service.
        ClipboardManager clipboard = (ClipboardManager)
            getSystemService(Context.CLIPBOARD_SERVICE);
    
        ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri);
    
        // Sets the clipboard's primary clip.
        clipboard.setPrimaryClip(clip);
    
  3. בהיקף הגלובלי של ספק התוכן, יש ליצור התאמת URI ולהוסיף דפוס URI תואם ל-URI שהוספת ללוח.

    Kotlin

    // A Uri Match object that simplifies matching content URIs to patterns.
    private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
    
        // Adds a matcher for the content URI. It matches.
        // "content://com.example.contacts/copy/*"
        addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT)
    }
    
    // An integer to use in switching based on the incoming URI pattern.
    private const val GET_SINGLE_CONTACT = 0
    ...
    class MyCopyProvider : ContentProvider() {
        ...
    }
    

    Java

    public class MyCopyProvider extends ContentProvider {
        ...
    // A Uri Match object that simplifies matching content URIs to patterns.
    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    
    // An integer to use in switching based on the incoming URI pattern.
    private static final int GET_SINGLE_CONTACT = 0;
    ...
    // Adds a matcher for the content URI. It matches
    // "content://com.example.contacts/copy/*"
    sUriMatcher.addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT);
    
  4. הגדרת query() . שיטה זו יכולה לטפל בדפוסי URI שונים, בהתאם לאופן שבו קודם אותם, אבל רק מופיעה הדפוס של פעולת ההעתקה מהלוח.

    Kotlin

    // Sets up your provider's query() method.
    override fun query(
            uri: Uri,
            projection: Array<out String>?,
            selection: String?,
            selectionArgs: Array<out String>?,
            sortOrder: String?
    ): Cursor? {
        ...
        // When based on the incoming content URI:
        when(sUriMatcher.match(uri)) {
    
            GET_SINGLE_CONTACT -> {
    
                // Queries and returns the contact for the requested name. Decodes
                // the incoming URI, queries the data model based on the last name,
                // and returns the result as a Cursor.
            }
        }
        ...
    }
    

    Java

    // Sets up your provider's query() method.
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
        String sortOrder) {
        ...
        // Switch based on the incoming content URI.
        switch (sUriMatcher.match(uri)) {
    
        case GET_SINGLE_CONTACT:
    
            // Queries and returns the contact for the requested name. Decodes the
            // incoming URI, queries the data model based on the last name, and
            // returns the result as a Cursor.
        ...
    }
    
  5. הגדרה של השיטה getType() להחזרת סוג MIME מתאים להעתקה נתונים:

    Kotlin

    // Sets up your provider's getType() method.
    override fun getType(uri: Uri): String? {
        ...
        return when(sUriMatcher.match(uri)) {
            GET_SINGLE_CONTACT -> MIME_TYPE_CONTACT
            ...
        }
    }
    

    Java

    // Sets up your provider's getType() method.
    public String getType(Uri uri) {
        ...
        switch (sUriMatcher.match(uri)) {
        case GET_SINGLE_CONTACT:
            return (MIME_TYPE_CONTACT);
        ...
        }
    }
    

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

העתקה של מקורות הנתונים

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

  • קבצים שמאוחסנים במכשיר עצמו
  • שידורים משקעים
  • כמויות גדולות של נתונים שמאוחסנים במערכת מסדי הנתונים הבסיסית של ספק

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

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

  1. מגדירים URI של תוכן עבור מקור הנתונים שמוסיפים ללוח. אפשרויות לשם כך:
    • מקודדים מזהה של מקור הנתונים ב-URI, כפי שמתואר במקטע לקודד מזהה בקטע ה-URI, ולאחר מכן לשמור על טבלה בספק שלכם שמכילה מזהים ואת השם של מקור הנתונים התואם.
    • מקודדים את שם מקור הנתונים ישירות ב-URI.
    • משתמשים ב-URI ייחודי תמיד שמחזיר את השידור הנוכחי מהספק. אם להשתמש באפשרות הזו, וזכרו לעדכן את הספק כך שיפנה לשידור אחר בכל פעם שמעתיקים את השידור ללוח באמצעות ה-URI.
  2. צריך לספק סוג MIME לכל סוג של מקור נתונים שמתכננים להציע. מדביק אפליקציות נדרש המידע הזה כדי לקבוע אם ניתן להדביק את הנתונים בלוח.
  3. להטמיע אחת מהשיטות ContentProvider שמחזירות קובץ תיאור של זרם. אם אתם מקודדים מזהים ב-URI של התוכן, השתמשו בשיטה זו כדי לקבוע אילו כדי לפתוח את השידור.
  4. כדי להעתיק את מקור הנתונים ללוח, יש ליצור את ה-URI של התוכן ולהציב אותו לוח העריכה.

כדי להדביק מקור נתונים, אפליקציה מקבלת את הקליפ מהלוח, מקבלת את ה-URI ומשתמשת באמצעות קריאה לשיטה לתיאור קובץ ContentResolver שפותחת את השידור. ה-method ContentResolver מפעילה את ה-method המתאים של ContentProvider, ומעבירים את ה-URI של התוכן. הספק מחזיר את מתאר הקובץ אל אמצעי תשלום אחד (ContentResolver). לאחר מכן, לאפליקציה ההדבקה יש אחריות לקרוא את מהזרם.

ברשימה הבאה מפורטות השיטות החשובות ביותר לתיאור קבצים של ספק התוכן. כל אחד מהם יש שיטת ContentResolver תואמת עם המחרוזת 'Descriptor' נוסף לשם ה-method. לדוגמה, ContentResolver אנלוגי של openAssetFile() תואם לערך openAssetFileDescriptor().

openTypedAssetFile()

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

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

openAssetFile()
השיטה הזו היא צורה כללית יותר של openTypedAssetFile(). ללא סינון לסוגי MIME מותרים, אך הוא יכול לקרוא קטעי משנה של קבצים.
openFile()
זהו צורה כללית יותר של openAssetFile(). הוא לא יכול לקרוא תתי-סעיפים של .

אפשר גם להשתמש openPipeHelper() באמצעות רכיב descriptor של הקובץ. כך האפליקציה ההדבקה יכולה לקרוא את נתוני הזרם שרשור ברקע באמצעות קו אנכי. כדי להשתמש בשיטה הזו, צריך להטמיע את ContentProvider.PipeDataWriter גרפי.

עיצוב פונקציונליות יעילה של העתקה והדבקה

כדי לתכנן פונקציונליות יעילה של העתקה והדבקה עבור האפליקציה, כדאי לזכור את הנקודות הבאות:

  • תמיד יש רק קליפ אחד בלוח. פעולת העתקה חדשה על ידי באפליקציה במערכת מחליפה את הקליפ הקודם. מאחר שהמשתמש עשוי לנווט מחוץ לאפליקציה ולהעתיק לפני החזרה, לא תוכלו להניח את הלוח מכיל את הקליפ שהמשתמש העתיק בעבר באפליקציה שלך.
  • המטרה של מספר אובייקטים מסוג ClipData.Item בכל קליפ היא לתמוך בהעתקה ובהדבקה של כמה אפשרויות בחירה במקום בצורות שונות הפניה לבחירה אחת. בדרך כלל אתה רוצה את כל הClipData.Item לאובייקטים בקליפ להיות באותו צורה. כלומר, הם חייבים להיות טקסט פשוט, תוכן URI, או Intent, ולא מעורבים.
  • כשאתם מספקים נתונים, אתם יכולים להציע ייצוגי MIME שונים. הוספה של סוגי MIME תומכים ב-ClipDescription, ואז להטמיע את סוגי ה-MIME ספק התוכן שלך.
  • כשמקבלים נתונים מהלוח, האפליקציה אחראית לבדוק את סוגי MIME הזמינים ולאחר מכן להחליט באיזה מהם להשתמש, אם בכלל. גם אם יש מהלוח העריכה והמשתמש מבקש לבצע הדבקה, האפליקציה לא נדרשת כדי לבצע את ההדבקה. מבצעים את ההדבקה אם סוג ה-MIME תואם. אפשר לאלץ את הנתונים בלוח כדי לשלוח טקסט באמצעות coerceToText(). אם האפליקציה תומכת יש יותר מאחד מסוגי MIME הזמינים, ואפשר לאפשר למשתמש לבחור באיזה מהם להשתמש.