کاربران اغلب میخواهند بااستفاده از اموجی، برچسب، و انواع دیگر محتوای غنی ارتباط برقرار کنند. در نسخههای قبلی Android، صفحهکلیدهای نرمافزاری (که با نام ویرایشگرهای روش ورودی یا IME نیز شناخته میشوند) فقط میتوانستند اموجی یونیکد به برنامهها ارسال کنند. برای محتوای غنی، برنامهها میاناهای برنامهسازی کاربردی مختص برنامه را میساختند که نمیشد در برنامههای دیگر استفاده کرد یا از راهحلهای جایگزین مثل ارسال تصاویر ازطریق کنش همرسانی ساده یا بریدهدان استفاده میکردند.
از Android 7.1 (سطح API ۲۵)، کیت توسعه نرمافزار Android شامل Commit Content API است که روشی جهانی برای IMEها فراهم میکند تا تصاویر و سایر محتوای غنی را مستقیماً به ویرایشگر نوشتار در برنامه ارسال کنند. این API همچنین در v13 Support Library از نسخه ۲۵.۰.۰ دردسترس است. توصیه میکنیم از «کتابخانه پشتیبانی» استفاده کنید زیرا حاوی روشهای کمکی است که پیادهسازی را ساده میکند.
با این میانای برنامهسازی کاربردی، میتوانید برنامههای پیامرسانی بسازید که محتوای غنی را از هر صفحهکلیدی بپذیرند و همچنین صفحهکلیدهایی بسازید که بتوانند محتوای غنی را به هر برنامهای ارسال کنند. صفحهکلید Google و برنامههایی مانند پیامنگار Google از Commit Content API در Android 7.1 پشتیبانی میکنند، همانطور که در شکل ۱ نشان داده شده است.
این سند نحوه پیادهسازی Commit Content API را در IME و برنامهها نشان میدهد.
روش کار
درج تصویر صفحهکلید به مشارکت IME و برنامه نیاز دارد. توالی زیر هر مرحله را در فرایند درج تصویر شرح میدهد:
وقتی کاربر روی
EditTextتکضرب میزند، ویرایشگر فهرستی از انواع محتوای MIME را که میپذیرد درEditorInfo.contentMimeTypesارسال میکند.IME فهرست انواع پشتیبانیشده را میخواند و محتوا را در صفحهکلید نرمافزاری که ویرایشگر میتواند بپذیرد نمایش میدهد.
وقتی کاربر تصویری را انتخاب میکند، IME
commitContent()را فراخوانی میکند وInputContentInfoرا به ویرایشگر ارسال میکند. فراخوانیcommitContent()مشابه فراخوانیcommitText()است، اما برای محتوای غنی.InputContentInfoحاوی URI است که محتوا را در ارائهدهنده محتوا شناسایی میکند.
این فرایند در شکل ۲ نشان داده شده است:
افزودن پشتیبانی از تصویر به برنامهها
برای پذیرش محتوای غنی از IME، برنامه باید به IME بگوید چه نوع محتوایی را میپذیرد و روش callback را که هنگام دریافت محتوا اجرا میشود مشخص کند.
مثال زیر نشان میدهد که چگونه میتوان یک EditText ایجاد کرد که تصاویر PNG را میپذیرد:
کاتلین
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 } }
جاوا
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; } };
در زیر توضیح بیشتری ارائه شده است:
این مثال از «کتابخانه پشتیبانی» استفاده میکند، بنابراین چند ارجاع به
android.support.v13.view.inputmethodبهجایandroid.view.inputmethodوجود دارد.این مثال یک
EditTextایجاد میکند و روشonCreateInputConnection(EditorInfo)آن را لغو میکند تاInputConnectionرا اصلاح کند.InputConnectionکانال ارتباطی بین IME و برنامهای است که ورودی آن را دریافت میکند.فراخوانی
super.onCreateInputConnection()رفتار داخلی (ارسال و دریافت نوشتار) را حفظ میکند و مرجعی بهInputConnectionبه شما میدهد.setContentMimeTypes()فهرستی از انواع MIME پشتیبانیشده را بهEditorInfoاضافه میکند. پیشازsetContentMimeTypes()باsuper.onCreateInputConnection()تماس بگیرید.callbackهروقت IME محتوا را نهایی کند اجرا میشود. روشonCommitContent()بهInputContentInfoCompatارجاع دارد که حاوی شناسه منبع یکسان محتوا است.- اگر برنامهتان در سطح میانای برنامهسازی کاربردی ۲۵ یا بالاتر اجرا میشود و پرچم
INPUT_CONTENT_GRANT_READ_URI_PERMISSIONتوسط IME تنظیم شده است، اجازهها را درخواست و منتشر کنید. درغیراینصورت، ازقبل به شناسه منبع یکسان محتوا دسترسی دارید زیرا IME آن را اعطا کرده است یا ارائهدهنده محتوا دسترسی را محدود نمیکند. برای اطلاعات بیشتر، به افزودن پشتیبانی تصویر به IME مراجعه کنید.
- اگر برنامهتان در سطح میانای برنامهسازی کاربردی ۲۵ یا بالاتر اجرا میشود و پرچم
createWrapper()InputConnection،EditorInfoاصلاحشده، و فراخوانی برگشتی را درInputConnectionجدیدی میپیچد و آن را برمیگرداند.
موارد زیر شیوههای توصیهشده هستند:
ویرایشگرهایی که از محتوای غنی پشتیبانی نمیکنند،
setContentMimeTypes()را فراخوانی نمیکنند وEditorInfo.contentMimeTypesخود را رویnullتنظیم میکنند.اگر نوع MIME مشخصشده در
InputContentInfoبا هیچیک از انواع موردقبول ویرایشگرها مطابقت نداشته باشد، ویرایشگرها محتوا را نادیده میگیرند.محتوای غنی بر موقعیت مکاننمای نوشتار تأثیری نمیگذارد و از آن تأثیر نمیپذیرد. ویرایشگران میتوانند هنگام کار با محتوا، موقعیت مکاننما را نادیده بگیرند.
در روش
OnCommitContentListener.onCommitContent()ویرایشگر، میتوانیدtrueرا بهصورت ناهمگام، حتی قبلاز بار کردن محتوا، برگردانید.برخلاف نوشتار که میتواند قبلاز اعمال شدن در IME ویرایش شود، محتوای غنی بلافاصله اعمال میشود. اگر میخواهید به کاربران اجازه دهید محتوا را ویرایش یا حذف کنند، منطق را خودتان پیادهسازی کنید.
برای آزمایش کردن برنامهتان، مطمئن شوید دستگاه یا شبیهسازتان صفحهکلیدی دارد که میتواند محتوای غنی ارسال کند. میتوانید از «صفحهکلید Google» در Android نسخه ۷.۱ یا بالاتر استفاده کنید.
افزودن پشتیبانی از تصویر به IME
IMEهایی که میخواهند محتوای غنی به برنامهها ارسال کنند باید Commit Content API را پیادهسازی کنند، همانطور که در مثال زیر نشان داده شده است:
- لغو کردن
onStartInput()یاonStartInputView()و خواندن فهرست انواع محتوای پشتیبانیشده از ویرایشگر هدف. تکهکد زیر نشان میدهد که چگونه میتوان بررسی کرد که آیا ویرایشگر هدف تصاویر GIF را میپذیرد یا نه.
کاتلین
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. } }
جاوا
@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 را نشان میدهد.
کاتلین
// 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) }
جاوا
// 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، احتمالاً باید ارائهدهنده محتوای خودتان را برای پاسخ دادن به درخواستهای شناسه منبع یکسان محتوا پیادهسازی کنید. استثنا زمانی است که IME شما از محتوای
ارائهدهندگان محتوای موجود مانند
MediaStore پشتیبانی کند. برای کسب اطلاعات درباره
ساخت ارائهدهندگان محتوا، به اسناد ارائهدهنده
محتوا و ارائهدهنده
فایل مراجعه کنید.
اگر ارائهدهنده محتوای خودتان را میسازید، توصیه میکنیم آن را با تنظیم کردن
android:exported روی
false صادر نکنید. بهجای آن، با تنظیم
android:grantUriPermission
روی true، اعطای اجازه را در ارائهدهنده فعال کنید. سپس، IME شما میتواند هنگام ثبت محتوا، اجازههای دسترسی به شناسه منبع یکسان محتوا را اعطا کند. دو روش برای انجام این کار وجود دارد:
در Android 7.1 (سطح میانای برنامهسازی کاربردی ۲۵) و بالاتر، هنگام فراخوانی
commitContent()، پارامتر پرچم را رویINPUT_CONTENT_GRANT_READ_URI_PERMISSIONتنظیم کنید. سپس، شیءInputContentInfoکه برنامه دریافت میکند میتواند با فراخوانیrequestPermission()وreleasePermission()اجازههای خواندن موقت را درخواست و منتشر کند.در Android 7.0 (سطح میانای برنامهسازی کاربردی ۲۴) و پایینتر،
INPUT_CONTENT_GRANT_READ_URI_PERMISSIONنادیده گرفته میشود، بنابراین بهصورت دستی اجازه دسترسی به محتوا را اعطا کنید. یک راه برای انجام این کار استفاده ازgrantUriPermission()است، اما میتوانید سازوکار خودتان را که الزاماتتان را برآورده میکند پیادهسازی کنید.
برای آزمایش IME، مطمئن شوید دستگاه یا شبیهسازتان برنامهای دارد که بتواند محتوای غنی دریافت کند. میتوانید از برنامه Google Messenger در Android نسخه ۷.۱ یا بالاتر استفاده کنید.