تلقّي محتوى ثري

الشكل 1. توفّر واجهة برمجة التطبيقات الموحدة مكانًا واحدًا للتعامل مع المحتوى الوارد بغض النظر عن الآلية المحددة لواجهة المستخدم، مثل اللصق من قائمة اللمس مع الاستمرار أو استخدام السحب والإفلات.

يحب المستخدمون الصور والفيديوهات وغيرها من المحتوى التعبيري، ولكن ليس من السهل دائمًا إدراج هذا المحتوى ونقله إلى التطبيقات. لتبسيط حصول التطبيقات على المحتوى الوافي، يقدّم Android 12 (المستوى 31 لواجهة برمجة التطبيقات) واجهة برمجة تطبيقات موحَّدة تتيح لتطبيقك قبول المحتوى من أي مصدر مثل الحافظة أو لوحة المفاتيح أو السحب.

يمكنك إرفاق واجهة، مثل OnReceiveContentListener، بمكوّنات واجهة المستخدم والحصول على استدعاء عند إدراج المحتوى من خلال أي آلية. تصبح معاودة الاتصال المكان الوحيد للرمز البرمجي الذي لمعالجة استلام كل المحتوى، بدءًا من النص العادي والنمط ووصولاً إلى الترميز والصور والفيديوهات والملفات الصوتية وغيرها.

وللتوافق مع الأنظمة القديمة مع إصدارات Android السابقة، تتوفّر واجهة برمجة التطبيقات هذه أيضًا في الإصدار AndroidX، بدءًا من Core 1.7 وAppcompat 1.4 واللذين ننصحك باستخدامهما عند تنفيذ هذه الوظيفة.

نظرة عامة

مع واجهات برمجة التطبيقات الحالية الأخرى، تحتوي كل آلية واجهة مستخدم، مثل قائمة اللمس مع الاستمرار أو السحب، على واجهة برمجة تطبيقات خاصة بها. وهذا يعني أنّه عليك الدمج مع كل واجهة برمجة تطبيقات على حدة، وإضافة رمز مشابه لكل آلية تدرج المحتوى:

صورة تعرض الإجراءات المختلفة وواجهة برمجة التطبيقات النسبية المطلوب تنفيذها
الشكل 2. في السابق، كانت التطبيقات تنفّذ واجهة برمجة تطبيقات مختلفة لكل آلية واجهة مستخدم لإدراج المحتوى.

تدمج واجهة برمجة التطبيقات OnReceiveContentListener مسارات الرموز المختلفة هذه عن طريق إنشاء واجهة برمجة تطبيقات واحدة لتنفيذها، بحيث يمكنك التركيز على المنطق الخاص بالتطبيق والترك للمنصة مع ما تنفّذه:

صورة تعرض واجهة برمجة التطبيقات الموحّدة والمبسّطة
الشكل 3. تتيح لك واجهة برمجة التطبيقات الموحدة تنفيذ واجهة برمجة تطبيقات واحدة تتوافق مع جميع آليات واجهة المستخدم.

يعني هذا النهج أيضًا أنّه عند إضافة طرق جديدة لإدراج المحتوى إلى المنصة، لن تحتاج إلى إجراء تغييرات إضافية على الرمز لإتاحة الدعم لتطبيقك. وإذا كان تطبيقك يحتاج إلى تنفيذ تخصيص كامل لحالة استخدام معيّنة، سيظل بإمكانك استخدام واجهات برمجة التطبيقات الحالية التي تواصل العمل بالطريقة نفسها.

التنفيذ

واجهة برمجة التطبيقات هي واجهة أدوات استماع تستخدم طريقة واحدة، OnReceiveContentListener. لإتاحة الإصدارات القديمة من نظام Android الأساسي، ننصح باستخدام واجهة OnReceiveContentListener المتطابقة في مكتبة AndroidX Core.

لاستخدام واجهة برمجة التطبيقات، نفِّذ أداة الاستماع من خلال تحديد أنواع المحتوى التي يمكن لتطبيقك معالجتها:

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 للمحتوى الذي يتوافق مع تطبيقك، يمكنك تنفيذ باقي أنواع أدوات معالجة البيانات:

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 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) للمحتوى. قم بإعادة أي بيانات متبقية إلى التفويض بالتعامل مع تلك البيانات إلى النظام الأساسي.

بعد تنفيذ المستمع، قم بتعيينه على عناصر واجهة المستخدم المناسبة في تطبيقك:

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) للمحتوى في الحمولة التي يتم تمريرها إلى OnReceiveContentListener.

عادةً ما يعالج تطبيقك معرّفات الموارد المنتظمة (URI) للمحتوى في خدمة أو نشاط. ولإجراء عملية معالجة طويلة الأمد، يمكنك استخدام WorkManager. عند تنفيذ ذلك، يجب منح الأذونات للخدمة أو النشاط المستهدَف من خلال تمرير المحتوى باستخدام Intent.setClipData وضبط العلامة FLAG_GRANT_READ_URI_PERMISSION.

وبدلاً من ذلك، يمكنك استخدام سلسلة محادثات في الخلفية ضمن السياق الحالي لمعالجة المحتوى. في هذه الحالة، يجب الإشارة إلى عنصر payload الذي يتلقّاه المستمع للمساعدة في ضمان عدم إبطال النظام الأساسي الأذونات قبل أوانها.

طرق العرض المخصّصة

إذا كان تطبيقك يستخدم فئة فرعية مخصّصة من نوع View، احرص على عدم تجاوز OnReceiveContentListener.

إذا كانت فئة View تلغي الطريقة onCreateInputConnection، استخدِم واجهة برمجة التطبيقات Jetpack API InputConnectionCompat.createWrapper لضبط InputConnection.

إذا كانت فئة View تلغي الطريقة onTextContextMenuItem، يمكنك التفويض إلى Super عندما يكون العنصر في القائمة R.id.paste أو R.id.pasteAsPlainText.

مقارنة بواجهة برمجة التطبيقات لصور لوحة المفاتيح

ويمكنك اعتبار واجهة برمجة التطبيقات OnReceiveContentListener باعتبارها الإصدار التالي من واجهة برمجة تطبيقات صور لوحة المفاتيح الحالية. تدعم واجهة برمجة التطبيقات الموحدة هذه وظائف واجهة برمجة تطبيقات صورة لوحة المفاتيح بالإضافة إلى بعض الميزات الإضافية. يختلف توافق الأجهزة والميزات حسب ما إذا كنت تستخدم مكتبة Jetpack أو واجهات برمجة التطبيقات الأصلية من حزمة تطوير البرامج (SDK) لنظام التشغيل Android.

الجدول 1. الميزات ومستويات واجهة برمجة التطبيقات المتوافقة مع Jetpack.
الإجراء أو الميزة متوافقة مع واجهة برمجة التطبيقات لصور لوحة المفاتيح متاح من خلال واجهة برمجة التطبيقات الموحدة
إدراج شريحة من لوحة المفاتيح نعم (المستوى 13 من واجهة برمجة التطبيقات والمستويات الأعلى) نعم (المستوى 13 من واجهة برمجة التطبيقات والمستويات الأعلى)
الإدراج باستخدام اللصق من قائمة اللمس مع الاستمرار لا نعم
الإدراج باستخدام السحب والإفلات لا نعم (المستوى 24 من واجهة برمجة التطبيقات والمستويات الأعلى)
الجدول 2. الميزات المتاحة ومستويات واجهة برمجة التطبيقات المتاحة لواجهات برمجة التطبيقات الأصلية.
الإجراء أو الميزة متوافقة مع واجهة برمجة التطبيقات لصور لوحة المفاتيح متاح من خلال واجهة برمجة التطبيقات الموحدة
إدراج شريحة من لوحة المفاتيح نعم (المستوى 25 من واجهة برمجة التطبيقات والمستويات الأعلى) نعم (نظام التشغيل Android 12 والإصدارات الأحدث)
الإدراج باستخدام اللصق من قائمة اللمس مع الاستمرار لا
الإدراج باستخدام السحب والإفلات لا