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

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

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

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

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

نظرة عامة

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

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

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

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

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

التنفيذ

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

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

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

KotlinJava
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) للمحتوى. عرض أي بيانات متبقية لتحديد من سيتولى معالجة هذه البيانات

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

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

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

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

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

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

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

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

إذا كانت فئة View تلغي الأسلوب onCreateInputConnection ، استخدِم واجهة برمجة تطبيقات Jetpack 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 والإصدارات الأحدث)
الإدراج باستخدام اللصق من قائمة "النقر مع الاستمرار" لا
الإدراج باستخدام السحب والإفلات لا