کاربران اغلب می خواهند با استفاده از ایموجی، برچسب ها و دیگر انواع محتوای غنی ارتباط برقرار کنند. در نسخههای قبلی اندروید، صفحهکلیدهای نرم - که به عنوان ویرایشگرهای روش ورودی یا IME نیز شناخته میشوند، میتوانند فقط شکلکهای یونیکد را به برنامهها ارسال کنند. برای محتوای غنی، برنامهها APIهای مخصوص برنامه را ساختهاند که نمیتوان از آنها در برنامههای دیگر استفاده کرد یا از راهحلهایی مانند ارسال تصاویر از طریق اقدام به اشتراکگذاری ساده یا کلیپبورد استفاده میکرد.
با شروع Android 7.1 (سطح API 25)، Android SDK شامل Commit Content API است که راهی جهانی برای IME ها فراهم می کند تا تصاویر و سایر محتوای غنی را مستقیماً به یک ویرایشگر متن در یک برنامه ارسال کنند. API همچنین در نسخه 25.0.0 در کتابخانه پشتیبانی v13 موجود است. ما استفاده از کتابخانه پشتیبانی را توصیه می کنیم زیرا حاوی روش های کمکی است که پیاده سازی را ساده می کند.
با این API، میتوانید برنامههای پیامرسانی بسازید که محتوای غنی را از هر صفحهکلیدی بپذیرند و همچنین صفحهکلیدهایی که میتوانند محتوای غنی را به هر برنامهای ارسال کنند. صفحهکلید Google و برنامههایی مانند Messages توسط Google از Commit Content API در اندروید ۷.۱ پشتیبانی میکنند، همانطور که در شکل ۱ نشان داده شده است.
این سند نحوه پیاده سازی Commit Content API را هم در IME و هم در برنامه ها نشان می دهد.
چگونه کار می کند
درج تصویر صفحه کلید به مشارکت IME و برنامه نیاز دارد. دنباله زیر هر مرحله از فرآیند درج تصویر را شرح می دهد:
وقتی کاربر روی
EditText
ضربه میزند، ویرایشگر فهرستی از انواع محتوای MIME را که درEditorInfo.contentMimeTypes
میپذیرد ارسال میکند.IME لیست انواع پشتیبانی شده را می خواند و محتوایی را در صفحه کلید نرم که ویرایشگر می تواند بپذیرد نمایش می دهد.
هنگامی که کاربر یک تصویر را انتخاب می کند، IME
commitContent()
را فراخوانی می کند و یکInputContentInfo
را به ویرایشگر می فرستد.commitContent()
مشابه فراخوانیcommitText()
است، اما برای محتوای غنی.InputContentInfo
حاوی یک URI است که محتوای یک ارائه دهنده محتوا را شناسایی می کند.
این فرآیند در شکل 2 نشان داده شده است:
پشتیبانی از تصویر را به برنامه ها اضافه کنید
برای پذیرش محتوای غنی از IME، یک برنامه باید به IME ها بگوید که چه نوع محتوایی را می پذیرد و یک روش بازگشت به تماس را مشخص کند که هنگام دریافت محتوا اجرا می شود. مثال زیر نحوه ایجاد یک 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()
را فراخوانی کنید.هر زمان که IME محتوا را متعهد می کند،
callback
اجرا می شود. متدonCommitContent()
دارای ارجاع بهInputContentInfoCompat
است که حاوی یک URI محتوا است.- اگر برنامه شما روی سطح API 25 یا بالاتر اجرا می شود و پرچم
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
توسط IME تنظیم شده است، مجوزها را درخواست و آزاد کنید. در غیر این صورت، شما از قبل به URI محتوا دسترسی دارید زیرا توسط IME اعطا شده است یا به دلیل اینکه ارائه دهنده محتوا دسترسی را محدود نمی کند. برای اطلاعات بیشتر، به افزودن پشتیبانی تصویر به IME مراجعه کنید.
- اگر برنامه شما روی سطح API 25 یا بالاتر اجرا می شود و پرچم
createWrapper()
InputConnection
،EditorInfo
اصلاح شده و callback را در یکInputConnection
جدید می پیچد و آن را برمی گرداند.
اقدامات زیر توصیه می شود:
ویرایشگرهایی که محتوای غنی را پشتیبانی نمیکنند
setContentMimeTypes()
را صدا نمیکنند وEditorInfo.contentMimeTypes
خود راnull
میگذارند.اگر نوع MIME مشخص شده در
InputContentInfo
با هیچ یک از انواعی که آنها می پذیرند مطابقت نداشته باشد، ویرایشگرها محتوا را نادیده می گیرند.محتوای غنی بر موقعیت مکان نما متن تأثیر نمی گذارد و تحت تأثیر قرار نمی گیرد. ویراستاران می توانند موقعیت مکان نما را هنگام کار با محتوا نادیده بگیرند.
در متد
OnCommitContentListener.onCommitContent()
ویرایشگر، میتوانید به صورت ناهمزمان، حتی قبل از بارگیری محتوا،true
برگردانید.برخلاف متن، که میتوان آن را قبل از تعهد در IME ویرایش کرد، محتوای غنی بلافاصله متعهد میشود. اگر می خواهید به کاربران اجازه دهید محتوا را ویرایش یا حذف کنند، منطق را خودتان پیاده کنید.
برای آزمایش برنامهتان، مطمئن شوید که دستگاه یا شبیهسازتان صفحهکلیدی دارد که میتواند محتوای غنی ارسال کند. می توانید از صفحه کلید Google در اندروید 7.1 یا بالاتر استفاده کنید.
پشتیبانی تصویر را به 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، به احتمال زیاد باید ارائه دهنده محتوای خود را پیاده سازی کنید تا به درخواست های URI محتوا پاسخ دهید. استثنا این است که IME شما از محتوای ارائه دهندگان محتوای موجود مانند MediaStore
پشتیبانی کند. برای اطلاعات در مورد ساخت ارائه دهندگان محتوا، به ارائه دهنده محتوا و مستندات ارائه دهنده فایل مراجعه کنید.
اگر ارائه دهنده محتوای خود را می سازید، توصیه می کنیم با تنظیم android:exported
روی false
آن را صادر نکنید. در عوض، با تنظیم android:grantUriPermission
روی true
، اعطای مجوز را در ارائه دهنده فعال کنید. سپس، IME شما میتواند مجوز دسترسی به URI محتوا را در زمانی که محتوا متعهد است، اعطا کند. دو راه برای این کار وجود دارد:
در اندروید 7.1 (سطح API 25) و بالاتر، هنگام فراخوانی
commitContent()
، پارامتر پرچم را رویINPUT_CONTENT_GRANT_READ_URI_PERMISSION
تنظیم کنید. سپس، شیءInputContentInfo
که برنامه دریافت میکند، میتواند با فراخوانیrequestPermission()
وreleasePermission()
مجوزهای خواندن موقت را درخواست کند و آزاد کند.در Android 7.0 (سطح API 24) و پایینتر،
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
نادیده گرفته میشود، بنابراین به صورت دستی به محتوا مجوز بدهید. یکی از راههای انجام این کار باgrantUriPermission()
است، اما میتوانید مکانیسم خود را که نیازهای شما را برآورده میکند، پیادهسازی کنید.
برای آزمایش IME خود، مطمئن شوید که دستگاه یا شبیه ساز شما دارای برنامه ای است که می تواند محتوای غنی را دریافت کند. می توانید از برنامه مسنجر گوگل در اندروید 7.1 یا بالاتر استفاده کنید.