Пользователи часто хотят общаться с помощью эмодзи, стикеров и других видов мультимедийного контента. В предыдущих версиях Android экранные клавиатуры, также известные как редакторы методов ввода (IME), могли отправлять в приложения только эмодзи Unicode. Для передачи расширенного контента разработчики создавали специальные API, которые нельзя было использовать в других приложениях, или применяли обходные пути, например отправляли изображения через простое действие по отправке или буфер обмена.
Начиная с Android 7.1 (уровень API 25), Android SDK включает Commit Content API, который предоставляет универсальный способ для IME отправлять изображения и другой расширенный контент непосредственно в текстовый редактор в приложении. API также доступен в библиотеке поддержки v13, начиная с версии 25.0.0. Мы рекомендуем использовать библиотеку поддержки, поскольку в ней есть вспомогательные методы, упрощающие реализацию.
С помощью этого API вы можете создавать приложения для обмена сообщениями, которые принимают расширенный контент с любой клавиатуры, а также клавиатуры, которые могут отправлять расширенный контент в любое приложение. Google Клавиатура и такие приложения, как Google Сообщения, поддерживают Commit Content API в Android 7.1, как показано на рисунке 1.
В этом документе рассказывается, как реализовать Commit Content API в редакторах методов ввода и приложениях.
Принцип работы
Для вставки изображений с клавиатуры требуется участие редактора метода ввода и приложения. Ниже описаны все этапы этого процесса.
Когда пользователь нажимает на
EditText, редактор отправляет список MIME-типов контента, которые он принимает, вEditorInfo.contentMimeTypes.Редактор метода ввода считывает список поддерживаемых типов и отображает на экранной клавиатуре контент, который может принять редактор.
Когда пользователь выбирает изображение, IME вызывает
commitContent()и отправляетInputContentInfoв редактор. ВызовcommitContent()аналогичен вызовуcommitText(), но предназначен для расширенных сведений о товаре.InputContentInfoсодержит URI, который идентифицирует контент в поставщике контента.
Этот процесс показан на рисунке 2:
Добавьте поддержку изображений в приложения
Чтобы принимать расширенный контент от редакторов методов ввода, приложение должно сообщать им, какие типы контента оно принимает, и указывать метод обратного вызова, который выполняется при получении контента.
В примере ниже показано, как создать 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; } };
Ниже приведены дополнительные пояснения.
В этом примере используется библиотека поддержки, поэтому в нем есть ссылки на
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 контента.- Запрашивайте и предоставляйте разрешения, если приложение работает на уровне API 25 или выше и IME устанавливает флаг
INPUT_CONTENT_GRANT_READ_URI_PERMISSION. В противном случае у вас уже есть доступ к URI контента, поскольку он предоставлен IME или поставщик контента не ограничивает доступ. Подробнее о том, как добавить поддержку изображений в IME…
- Запрашивайте и предоставляйте разрешения, если приложение работает на уровне API 25 или выше и IME устанавливает флаг
createWrapper()упаковываетInputConnection, измененныйEditorInfoи обратный вызов в новыйInputConnectionи возвращает его.
Рекомендуем сделать следующее:
Редакторы, которые не поддерживают расширенные сведения о товаре, не вызывают
setContentMimeTypes()и оставляют дляEditorInfo.contentMimeTypesзначениеnull.Редакторы игнорируют контент, если MIME-тип, указанный в
InputContentInfo, не соответствует ни одному из типов, которые они принимают.Положение текстового курсора не влияет на расширенные сведения о товаре и не зависит от них. Редакторы могут игнорировать положение курсора при работе с контентом.
В методе
OnCommitContentListener.onCommitContent()редактора можно асинхронно возвращатьtrue, даже до загрузки контента.В отличие от текста, который можно редактировать в IME перед отправкой, расширенный контент отправляется сразу. Если вы хотите, чтобы пользователи могли редактировать или удалять контент, реализуйте эту логику самостоятельно.
Чтобы протестировать приложение, убедитесь, что на вашем устройстве или эмуляторе есть клавиатура, которая может отправлять расширенный контент. Google Клавиатура доступна на устройствах с Android 7.1 и более поздними версиями ОС.
Добавьте поддержку изображений в редакторы методов ввода
Редакторы методов ввода, которые должны отправлять расширенный контент в приложения, должны реализовывать 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. Затем редактор метода ввода может предоставить разрешения на доступ к URI контента, когда контент будет зафиксирован. Сделать это можно двумя способами:
На устройствах с Android 7.1 (уровень API 25) и более поздними версиями при вызове
commitContent()установите для параметра flag значениеINPUT_CONTENT_GRANT_READ_URI_PERMISSION. Затем объектInputContentInfo, который получает приложение, может запрашивать и отменять временные разрешения на чтение, вызывая методыrequestPermission()иreleasePermission().В Android 7.0 (уровень API 24) и более ранних версиях
INPUT_CONTENT_GRANT_READ_URI_PERMISSIONигнорируется, поэтому разрешение на доступ к контенту нужно предоставлять вручную. Один из способов сделать это – использоватьgrantUriPermission(), но вы можете реализовать собственный механизм, отвечающий вашим требованиям.
Чтобы протестировать редактор метода ввода, убедитесь, что на вашем устройстве или эмуляторе есть приложение, которое может получать расширенный контент. Приложение Google Messenger можно использовать на устройствах с Android 7.1 и более поздними версиями.