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

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

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

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

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

نظرة عامة

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

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

تدمج واجهة برمجة التطبيقات 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<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;
     }
 }

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

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

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

أذونات عناوين URL

وتمنح المنصة أذونات القراءة وتصدرها تلقائيًا لأي معرّفات موارد منتظمة (URI) للمحتوى في الحمولة التي يتم تمريرها إلى OnReceiveContentListener.

يعالج تطبيقك عادةً معرّفات الموارد المنتظمة للمحتوى في خدمة أو نشاط. بالنسبة إلى المعالجة التي تستغرق وقتًا طويلاً، استخدِم 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 والإصدارات الأحدث)
الإدراج باستخدام اللصق من قائمة "النقر مع الاستمرار" لا
الإدراج باستخدام السحب والإفلات لا