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

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

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

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

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

نمای کلی

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

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

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

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

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

پیاده‌سازی

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

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

کاتلین

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

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

به عنوان یک روش جایگزین، می‌توانید از یک نخ پس‌زمینه در چارچوب فعلی برای پردازش محتوا استفاده کنید. در این حالت، باید یک ارجاع به شیء payload دریافت شده توسط شنونده (listener) داشته باشید تا اطمینان حاصل شود که مجوزها توسط پلتفرم به طور زودهنگام لغو نمی‌شوند.

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

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

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

اگر کلاس View شما متد onTextContextMenuItem override می‌کند، وقتی آیتم منو R.id.paste یا R.id.pasteAsPlainText است، آن را به super واگذار کنید.

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

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

جدول ۱. ویژگی‌ها و سطوح API پشتیبانی‌شده برای جت‌پک.
اقدام یا ویژگی پشتیبانی شده توسط API تصویر صفحه کلید پشتیبانی شده توسط API یکپارچه
از صفحه کلید وارد کنید بله (سطح API 13 و بالاتر) بله (سطح API 13 و بالاتر)
با استفاده از چسباندن از منوی لمس و نگه داشتن، درج کنید خیر بله
درج با استفاده از کشیدن و رها کردن خیر بله (سطح API 24 و بالاتر)
جدول 2. ویژگی‌ها و سطوح API پشتیبانی‌شده برای APIهای بومی.
اقدام یا ویژگی پشتیبانی شده توسط API تصویر صفحه کلید پشتیبانی شده توسط API یکپارچه
از صفحه کلید وارد کنید بله (سطح API 25 و بالاتر) بله (اندروید ۱۲ و بالاتر)
با استفاده از چسباندن از منوی لمس و نگه داشتن، درج کنید خیر
با استفاده از کشیدن و رها کردن، درج کنید خیر