دریافت محتوای غنی

شکل ۱. ‫Unified API مکانی واحد برای مدیریت محتوای ورودی بدون توجه به سازوکار خاص میانای کاربر ارائه می‌دهد، مانند جای‌گذاری از منو لمس کردن و نگه داشتن یا استفاده از کشیدن و رها کردن.

کاربران تصاویر، ویدیوها، و دیگر محتوای بیانی را دوست دارند، اما درج و انتقال این محتوا در برنامه‌ها همیشه آسان نیست. برای اینکه دریافت محتوای غنی برای برنامه‌ها ساده‌تر شود، Android 12 (میانای برنامه‌سازی کاربردی سطح ۳۱) میانای برنامه‌سازی کاربردی یکپارچه‌ای را معرفی می‌کند که به برنامه شما اجازه می‌دهد محتوا را از هر منبعی بپذیرد: بریده‌دان، صفحه‌کلید، یا کشیدن.

می‌توانید واسطی مثل OnReceiveContentListener را به مؤلفه‌های واسط کاربر پیوست کنید و وقتی محتوا ازطریق هر سازوکاری درج شد، فراخوانی برگشتی دریافت کنید. فراخوانی برگشتی به تنها جایی تبدیل می‌شود که کد شما می‌تواند دریافت همه محتواها را مدیریت کند، از نوشتار ساده و سبک‌دار گرفته تا نشانه‌گذاری، تصاویر، ویدیوها، فایل‌های صوتی، و غیره.

برای سازگاری با نسخه‌های قبلی Android، این میانای برنامه‌سازی کاربردی در AndroidX نیز دردسترس است، از Core 1.7 و Appcompat 1.4 شروع می‌شود، که توصیه می‌کنیم هنگام پیاده‌سازی این عملکرد از آن استفاده کنید.

نمای کلی

با دیگر میاناهای برنامه‌سازی کاربردی موجود، هر سازوکار واسط کاربر (مثل منو لمس کردن و نگه داشتن یا کشیدن) میانای برنامه‌سازی کاربردی متناظر خودش را دارد. این یعنی باید با هر میانای برنامه‌سازی کاربردی به‌طور جداگانه ادغام کنید و برای هر سازوکاری که محتوا درج می‌کند کد مشابهی اضافه کنید:

تصویری که کنش‌های مختلف و API مربوطه را برای پیاده‌سازی نشان می‌دهد
شکل ۲. قبلاً، برنامه‌ها برای هر سازوکار میانای کاربر برای درج محتوا، API متفاوتی را پیاده‌سازی می‌کردند.

OnReceiveContentListener API این مسیرهای کد مختلف را با ایجاد یک API واحد برای پیاده‌سازی ادغام می‌کند، بنابراین می‌توانید روی منطق خاص برنامه خود تمرکز کنید و اجازه دهید پلتفرم بقیه کارها را انجام دهد:

تصویری که API یکپارچه ساده‌شده را نشان می‌دهد
شکل ۳. میانای برنامه‌سازی کاربردی یکپارچه به شما امکان می‌دهد یک میانای برنامه‌سازی کاربردی واحد را پیاده‌سازی کنید که از همه سازوکارهای واسط کاربر پشتیبانی می‌کند.

این رویکرد همچنین به این معنی است که وقتی روش‌های جدیدی برای درج محتوا به پلاتفرم اضافه می‌شود، نیازی به ایجاد تغییرات کد اضافی برای فعال کردن پشتیبانی در برنامه‌تان ندارید. و اگر برنامه‌تان نیاز به پیاده‌سازی سفارشی‌سازی کامل برای یک مورد استفاده خاص دارد، همچنان می‌توانید از میاناهای برنامه‌سازی کاربردی موجود استفاده کنید که به همان روش به کار خود ادامه می‌دهند.

پیاده‌سازی

این میانای برنامه‌سازی کاربردی یک میانای شنونده با یک روش واحد است، OnReceiveContentListener. برای پشتیبانی از نسخه‌های قدیمی‌تر پلاتفرم Android، توصیه می‌کنیم از میانای مطابق OnReceiveContentListener در کتابخانه AndroidX Core استفاده کنید.

برای استفاده از API، شنونده را با مشخص کردن انواع محتوایی که برنامه‌تان می‌تواند مدیریت کند پیاده‌سازی کنید:

کاتلین

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 محتوایی که برنامه‌تان پشتیبانی می‌کند، بقیه شنونده را پیاده‌سازی کنید:

کاتلین

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;
     }
 }

اگر برنامه‌تان ازقبل از هم‌رسانی با هدف‌ها پشتیبانی می‌کند، می‌توانید از منطق مختص برنامه‌تان برای مدیریت شناسه منبع یکسان محتوا استفاده کنید. هرگونه داده باقی‌مانده را به پلاتفرم برگردانید تا رسیدگی به آن داده‌ها را به پلاتفرم واگذار کنید.

پس‌از پیاده‌سازی شنونده، آن را روی عناصر میانای کاربر مناسب در برنامه‌تان تنظیم کنید:

کاتلین

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

اجازه‌های خواندن به‌طور خودکار توسط پلاتفرم برای هر شناسه منبع یکسان محتوا در بار داده منتقل‌شده به OnReceiveContentListener اعطا و صادر می‌شود.

معمولاً، برنامه‌تان شناسه منبع یکسان محتوا را در سرویس یا فعالیتی پردازش می‌کند. برای پردازش طولانی‌مدت، از WorkManager استفاده کنید. وقتی این را پیاده‌سازی می‌کنید، با ارسال محتوا بااستفاده از Intent.setClipData و تنظیم پرچم FLAG_GRANT_READ_URI_PERMISSION، اجازه‌ها را به سرویس یا فعالیت هدف گسترش دهید.

یا می‌توانید از رشته پس‌زمینه در بافت فعلی برای پردازش محتوا استفاده کنید. در این حالت، باید ارجاعی به شیء payload دریافتی توسط شنونده را حفظ کنید تا مطمئن شوید که اجازه‌ها پیش‌از موعد توسط پلاتفرم لغو نمی‌شوند.

نماهای سفارشی

اگر برنامه‌تان از زیرکلاس View سفارشی استفاده می‌کند، دقت کنید که OnReceiveContentListener دور زده نشود.

اگر کلاس View شما روش onCreateInputConnection را لغو می‌کند، از Jetpack API InputConnectionCompat.createWrapper برای پیکربندی InputConnection استفاده کنید.

If your View class overrides the onTextContextMenuItem method, delegate to super when the menu item is R.id.paste or R.id.pasteAsPlainText.

مقایسه با میانای برنامه‌سازی کاربردی تصویر صفحه‌کلید

می‌توانید OnReceiveContentListener API را به‌عنوان نسخه بعدی keyboard image API موجود درنظر بگیرید. این API یکپارچه از عملکرد API تصویر صفحه‌کلید و همچنین برخی ویژگی‌های اضافی پشتیبانی می‌کند. سازگاری دستگاه و ویژگی بسته به اینکه از کتابخانه Jetpack یا میاناهای برنامه‌سازی کاربردی بومی از کیت توسعه نرم‌افزار Android استفاده می‌کنید متفاوت است.

جدول ۱. ویژگی‌های پشتیبانی‌شده و سطوح میانای برنامه‌سازی کاربردی برای Jetpack.
کنش یا ویژگی پشتیبانی‌شده توسط میانای برنامه‌سازی کاربردی تصویر صفحه‌کلید پشتیبانی‌شده توسط میانای برنامه‌سازی کاربردی یکپارچه
درج از صفحه‌کلید بله (میانای برنامه‌سازی کاربردی سطح ۱۳ و بالاتر) بله (سطح میانای برنامه‌سازی کاربردی ۱۳ و بالاتر)
درج کردن بااستفاده از جای‌گذاری از منوی لمس کردن و نگه داشتن نه بله
درج کردن بااستفاده از کشیدن و رها کردن نه بله (سطح میانای برنامه‌سازی کاربردی ۲۴ و بالاتر)
جدول ۲. ویژگی‌های پشتیبانی‌شده و سطوح میانای برنامه‌سازی کاربردی برای میاناهای برنامه‌سازی کاربردی بومی.
کنش یا ویژگی پشتیبانی‌شده توسط میانای برنامه‌سازی کاربردی تصویر صفحه‌کلید پشتیبانی‌شده توسط میانای برنامه‌سازی کاربردی یکپارچه
درج از صفحه‌کلید بله (میانای برنامه‌سازی کاربردی سطح ۲۵ و بالاتر) بله (Android 12 و بالاتر)
درج کردن بااستفاده از جای‌گذاری از منوی لمس کردن و نگه داشتن نه
درج کردن بااستفاده از کشیدن و رها کردن نه