إتاحة لوحة المفاتيح للصور

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

صورة تعرض لوحة مفاتيح تتيح البحث بالصور
الشكل 1. مثال على إتاحة لوحة مفاتيح الصور

بدءًا من الإصدار 7.1 من نظام التشغيل Android (المستوى 25 من واجهة برمجة التطبيقات)، تتضمّن حزمة تطوير البرامج (SDK) لنظام التشغيل Android واجهة برمجة التطبيقات Commit Content API التي توفّر طريقة شاملة يمكن من خلالها لمستخدمي أسلوب الإدخال (IME) إرسال الصور والمحتوى الوافي الآخر مباشرةً إلى محرِّر نصوص في أحد التطبيقات. تتوفّر واجهة برمجة التطبيقات أيضًا في الإصدار 13 من مكتبة الدعم اعتبارًا من الإصدار 25.0.0. ننصح باستخدام مكتبة الدعم لأنها تحتوي على طرق مساعِدة تبسّط عملية التنفيذ.

باستخدام واجهة برمجة التطبيقات هذه، يمكنك إنشاء تطبيقات مراسلة تقبل المحتوى الوافي من أي لوحة مفاتيح، بالإضافة إلى لوحات مفاتيح يمكنها إرسال محتوى وافٍ إلى أي تطبيق. تتوافق لوحة مفاتيح Google وتطبيقات مثل الرسائل من Google مع Commit Content API في الإصدار 7.1 من نظام التشغيل Android، كما هو موضّح في الشكل 1.

يعرض هذا المستند كيفية تنفيذ Commit Content API في كل من أدوات IME والتطبيقات.

طريقة العمل

يتطلب إدراج صورة لوحة المفاتيح مشاركة من أداة IME والتطبيق. ويصف التسلسل التالي كل خطوة في عملية إدراج الصور:

  1. عندما ينقر المستخدم على EditText، يرسل المحرِّر قائمة بأنواع محتوى MIME التي يقبلها في EditorInfo.contentMimeTypes.

  2. تقرأ أداة IME قائمة الأنواع المتوافقة وتعرض المحتوى في لوحة المفاتيح الإلكترونية التي يمكن للمحرر قبولها.

  3. عندما يختار المستخدم صورة، تستدعي أداة IME commitContent() وترسل InputContentInfo إلى المحرر. تشبه استدعاء commitContent() طلب commitText()، ولكنّه يتضمن محتوًى وافيًا. يحتوي InputContentInfo على عنوان URI يحدّد المحتوى في موفّر المحتوى.

يوضح الشكل 2 هذه العملية:

صورة تعرض التسلسل من Application إلى IME والعودة إلى التطبيق (التطبيق).
الشكل 2. تطبيق على IME في تدفق التطبيق.

إتاحة الصور في التطبيقات

لقبول المحتوى المنسَّق من أدوات IME، يجب أن يُطلع التطبيق أدوات IME على أنواع المحتوى التي يقبلها، وأن يحدد طريقة لرد الاتصال يتم تنفيذها عند تلقي المحتوى. يوضّح المثال التالي كيفية إنشاء سمة EditText تقبل صور PNG:

Kotlin

var editText: EditText = object : EditText(this) {
    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
        var ic = super.onCreateInputConnection(outAttrs)
        EditorInfoCompat.setContentMimeTypes(outAttrs, arrayOf("image/png"))
        val mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this)
        if (mimeTypes != null) {
            EditorInfoCompat.setContentMimeTypes(outAttrs, mimeTypes)
            ic = InputConnectionCompat.createWrapper(this, ic, outAttrs)
        }
        return ic
    }
}

Java

EditText editText = new EditText(this) {
    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        InputConnection ic = super.onCreateInputConnection(outAttrs);
        EditorInfoCompat.setContentMimeTypes(outAttrs, new String[]{"image/png"});
        String[] mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this);
        if (mimeTypes != null) {
            EditorInfoCompat.setContentMimeTypes(outAttrs, mimeTypes);
            ic = InputConnectionCompat.createWrapper(this, ic, outAttrs);
        }
        return ic;
    }
};

فيما يلي المزيد من التوضيح:

  • يستخدم هذا المثال مكتبة Support Library، لذا هناك بعض الإشارات إلى العنصر android.support.v13.view.inputmethod بدلاً من android.view.inputmethod.

  • ينشئ هذا المثال EditText ويلغي طريقة onCreateInputConnection(EditorInfo) لتعديل InputConnection. وInputConnection هي قناة الاتصال بين أداة IME والتطبيق الذي يستقبل مدخلاته.

  • تحافظ المكالمة super.onCreateInputConnection() على السلوك المضمّن، أي إرسال الرسائل النصية واستلامها، وإعطائك إشارة إلى InputConnection.

  • يضيف setContentMimeTypes() قائمة بأنواع MIME المتوافقة إلى EditorInfo. يُرجى الاتصال بـ super.onCreateInputConnection() قبل setContentMimeTypes().

  • يتم تنفيذ callback عندما تنفذ أداة IME المحتوى. تتضمّن الطريقة onCommitContent() مرجعًا إلى InputContentInfoCompat، الذي يحتوي على معرّف موارد منتظم (URI) للمحتوى.

    • يمكنك طلب الأذونات وإصدارها إذا كان تطبيقك يعمل على المستوى 25 من واجهة برمجة التطبيقات أو مستوى أعلى، وتم ضبط العلامة INPUT_CONTENT_GRANT_READ_URI_PERMISSION من خلال أداة IME. بخلاف ذلك، يمكنك الوصول إلى معرّف الموارد المنتظم (URI) للمحتوى لأنّه تم منحه من خلال أداة IME أو لأنّ مزود المحتوى لا يحظر الوصول. ولمزيد من المعلومات، يُرجى الاطّلاع على إضافة دعم الصور إلى أدوات IME.
  • createWrapper() يتضمن InputConnection وقيمة EditorInfo المعدَّلة ومعاودة الاتصال في InputConnection جديد وتعرضها.

في ما يلي الممارسات المقترَحة:

  • إنّ المحرِّرين الذين لا يوفّرون المحتوى الوافي لا يتصلون بالرمز setContentMimeTypes()، ويتركون EditorInfo.contentMimeTypes مضبوطة على null.

  • يتجاهل المحرِّرون المحتوى إذا كان نوع MIME المحدّد في InputContentInfo لا يتطابق مع أي من الأنواع التي يقبلونها.

  • لا يؤثر المحتوى الغني بموضع مؤشر النص ولا يتأثر به. يمكن للمحررين تجاهل موضع المؤشر عند التعامل مع المحتوى.

  • في طريقة OnCommitContentListener.onCommitContent() في المحرِّر، يمكنك عرض true بشكل غير متزامن، حتى قبل تحميل المحتوى.

  • على عكس النص الذي يمكن تعديله في أداة IME قبل استخدامه، يتم الالتزام بالمحتوى الوافي على الفور. إذا كنت ترغب في السماح للمستخدمين بتعديل المحتوى أو حذفه، فنفِّذ المنطق بنفسك.

لاختبار تطبيقك، تأكد من احتواء الجهاز أو المحاكي على لوحة مفاتيح يمكنها إرسال محتوى وافٍ. يمكنك استخدام لوحة مفاتيح Google في الإصدار Android 7.1 أو الإصدارات الأحدث.

إضافة دعم الصور إلى أدوات IME

على أدوات IME التي تريد إرسال محتوى وافٍ إلى التطبيقات تنفيذ Commit Content API، كما هو موضّح في المثال التالي:

  • إلغاء onStartInput() أو onStartInputView() وقراءة قائمة أنواع المحتوى المتوافقة من المحرر المستهدف. يعرض مقتطف الرمز التالي كيفية التحقق مما إذا كان المحرر المستهدف يقبل صور GIF أم لا.

Kotlin

override fun onStartInputView(editorInfo: EditorInfo, restarting: Boolean) {
    val mimeTypes: Array<String> = EditorInfoCompat.getContentMimeTypes(editorInfo)

    val gifSupported: Boolean = mimeTypes.any {
        ClipDescription.compareMimeTypes(it, "image/gif")
    }

    if (gifSupported) {
        // The target editor supports GIFs. Enable the corresponding content.
    } else {
        // The target editor doesn't support GIFs. Disable the corresponding
        // content.
    }
}

Java

@Override
public void onStartInputView(EditorInfo info, boolean restarting) {
    String[] mimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo);

    boolean gifSupported = false;
    for (String mimeType : mimeTypes) {
        if (ClipDescription.compareMimeTypes(mimeType, "image/gif")) {
            gifSupported = true;
        }
    }

    if (gifSupported) {
        // The target editor supports GIFs. Enable the corresponding content.
    } else {
        // The target editor doesn't support GIFs. Disable the corresponding
        // content.
    }
}

  • تفعيل المحتوى في التطبيق عندما يختار المستخدم صورة تجنَّب طلب الرمز commitContent() عندما يتم إنشاء أي نص، لأنّ ذلك قد يؤدي إلى فقدان التركيز على المحرِّر. يوضح مقتطف التعليمة البرمجية التالي كيفية التقاط صورة GIF.

Kotlin

// Commits a GIF image.

// @param contentUri = Content URI of the GIF image to be sent.
// @param imageDescription = Description of the GIF image to be sent.

fun commitGifImage(contentUri: Uri, imageDescription: String) {
    val inputContentInfo = InputContentInfoCompat(
            contentUri,
            ClipDescription(imageDescription, arrayOf("image/gif")),
            null
    )
    val inputConnection = currentInputConnection
    val editorInfo = currentInputEditorInfo
    var flags = 0
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
        flags = flags or InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION
    }
    InputConnectionCompat.commitContent(inputConnection, editorInfo, inputContentInfo, flags, null)
}

Java

// Commits a GIF image.

// @param contentUri = Content URI of the GIF image to be sent.
// @param imageDescription = Description of the GIF image to be sent.

public static void commitGifImage(Uri contentUri, String imageDescription) {
    InputContentInfoCompat inputContentInfo = new InputContentInfoCompat(
            contentUri,
            new ClipDescription(imageDescription, new String[]{"image/gif"}),
            null
    );
    InputConnection inputConnection = getCurrentInputConnection();
    EditorInfo editorInfo = getCurrentInputEditorInfo();
    Int flags = 0;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
        flags |= InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
    }
    InputConnectionCompat.commitContent(
            inputConnection, editorInfo, inputContentInfo, flags, null);
}

بصفتك مؤلف أداة IME، ستحتاج على الأرجح إلى تنفيذ موفر المحتوى التابع لك للرد على طلبات معرّف الموارد المنتظم (URI) للمحتوى. يُستثنى من ذلك إذا كان محرر أسلوب الإدخال (IME) لديك يتيح استخدام المحتوى من مزودي المحتوى الحاليين مثل MediaStore. للحصول على معلومات عن إنشاء موفّري المحتوى، يُرجى الاطّلاع على مستندات موفّر المحتوى وموفِّر الملفات.

في حال إنشاء موفّر محتوى خاص بك، ننصحك بعدم تصديره من خلال ضبط android:exported على false. بدلاً من ذلك، عليك تفعيل ميزة منح الأذونات في مقدّم الخدمة من خلال ضبط android:grantUriPermission على true. وبعد ذلك، يمكن لأداة IME منح أذونات الوصول إلى معرّف الموارد المنتظم للمحتوى (URI) للمحتوى الذي يتم الالتزام به. ثمة طريقتان لتنفيذ هذا الإجراء:

  • في نظام التشغيل Android 7.1 (المستوى 25 لواجهة برمجة التطبيقات) والإصدارات الأحدث، اضبط معلَمة العلامة على INPUT_CONTENT_GRANT_READ_URI_PERMISSION عند طلب البيانات من commitContent(). بعد ذلك، يمكن لكائن InputContentInfo الذي يتلقّاه التطبيق طلب أذونات قراءة مؤقتة وإصدارها من خلال استدعاء requestPermission() و releasePermission().

  • في نظام التشغيل Android 7.0 (مستوى واجهة برمجة التطبيقات 24) والإصدارات الأقدم، يتم تجاهل INPUT_CONTENT_GRANT_READ_URI_PERMISSION، لذا عليك منح الإذن يدويًا بالمحتوى. يمكنك إجراء ذلك باستخدام grantUriPermission()، ولكن يمكنك تنفيذ آلية خاصة بك تلبّي متطلباتك.

لاختبار أداة IME، تأكد من أن جهازك أو المحاكي به تطبيق يمكنه تلقي محتوى وافٍ. يمكنك استخدام تطبيق مراسلة Google في الإصدار Android 7.1 أو الإصدارات الأحدث.