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

الشكل 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 Chat عندما يكون عنصر القائمة R.id.paste أو R.id.pasteAsPlainText.

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

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

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