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

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

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

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

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

نمای کلی

با دیگر APIهای موجود، هر مکانیزم UI - مانند منوی لمس و نگه داشتن یا کشیدن - دارای API مربوط به خود است. این بدان معنی است که شما باید با هر API به طور جداگانه یکپارچه شوید و برای هر مکانیزمی که محتوا را درج می کند کد مشابهی اضافه کنید:

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

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

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

این رویکرد همچنین به این معنی است که وقتی روش‌های جدیدی برای درج محتوا به پلتفرم اضافه می‌شود، نیازی به تغییر کد اضافی برای فعال کردن پشتیبانی در برنامه خود ندارید. و اگر برنامه شما نیاز به پیاده سازی سفارشی سازی کامل برای یک مورد خاص دارد، همچنان می توانید از 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;
     }
 }

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

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

کاتلین

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 محتوای موجود در بار ارسال شده به OnReceiveContentListener اعطا می شود و منتشر می شود.

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

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

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

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

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

اگر کلاس View شما روش onTextContextMenuItem لغو می‌کند، زمانی که آیتم منو R.id.paste یا R.id.pasteAsPlainText است، به super تفویض کنید.

مقایسه با 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 یکپارچه پشتیبانی می شود
درج از صفحه کلید بله (سطح API 25 و بالاتر) بله (اندروید 12 و بالاتر)
با استفاده از چسباندن از منوی لمس و نگه دارید، درج کنید خیر
با استفاده از کشیدن و رها کردن درج کنید خیر