Người dùng thường muốn giao tiếp bằng biểu tượng cảm xúc, hình dán và các loại nội dung đa dạng thức khác. Trong các phiên bản Android trước, bàn phím mềm (còn gọi là trình chỉnh sửa phương thức nhập hoặc IME) chỉ có thể gửi biểu tượng cảm xúc Unicode đến các ứng dụng. Đối với nội dung đa dạng thức, ứng dụng đã tạo các API dành riêng cho ứng dụng mà không thể dùng trong các ứng dụng khác hoặc đã sử dụng các giải pháp như gửi hình ảnh thông qua thao tác chia sẻ đơn giản hoặc bảng nhớ tạm.
![Hình ảnh cho thấy bàn phím hỗ trợ tính năng tìm kiếm bằng hình ảnh](https://developer.android.com/static/images/guide/topics/text/image-keyboard-sample.png?authuser=5&hl=vi)
Kể từ Android 7.1 (API cấp 25), SDK Android bao gồm Commit Content API, cung cấp một cách thức chung để IME gửi hình ảnh và nội dung đa dạng thức khác trực tiếp tới trình chỉnh sửa văn bản trong ứng dụng. API cũng có trong Thư viện hỗ trợ v13 kể từ bản sửa đổi 25.0.0. Bạn nên sử dụng Thư viện hỗ trợ vì thư viện này chứa các phương thức trợ giúp giúp đơn giản hoá quá trình triển khai.
Với API này, bạn có thể tạo các ứng dụng nhắn tin chấp nhận nội dung đa dạng thức từ mọi bàn phím, cũng như bàn phím có thể gửi nội dung đa dạng thức đến bất kỳ ứng dụng nào. Bàn phím Google và các ứng dụng như Tin nhắn của Google hỗ trợ Commit Content API trong Android 7.1, như minh hoạ trong hình 1.
Tài liệu này trình bày cách triển khai Commit Content API trong cả IME và ứng dụng.
Cách hoạt động
Tính năng chèn hình ảnh trên bàn phím cần có sự tham gia của IME và ứng dụng. Trình tự sau đây mô tả từng bước trong quy trình chèn hình ảnh:
Khi người dùng nhấn vào một
EditText
, trình chỉnh sửa sẽ gửi danh sách các loại nội dung MIME được chấp nhận trongEditorInfo.contentMimeTypes
.IME đọc danh sách các loại được hỗ trợ và hiển thị nội dung trong bàn phím mềm mà trình chỉnh sửa có thể chấp nhận.
Khi người dùng chọn một hình ảnh, IME sẽ gọi
commitContent()
và gửiInputContentInfo
đến trình chỉnh sửa. Lệnh gọicommitContent()
tương tự như lệnh gọicommitText()
nhưng dành cho nội dung đa dạng thức.InputContentInfo
chứa URI xác định nội dung trong một trình cung cấp nội dung.
Quá trình này được mô tả trong hình 2:
![Hình ảnh hiển thị trình tự từ Application đến IME và quay lại Application](https://developer.android.com/static/images/guide/topics/text/image-keyboard-diagram.png?authuser=5&hl=vi)
Thêm tính năng hỗ trợ hình ảnh vào ứng dụng
Để chấp nhận nội dung đa dạng thức từ IME, ứng dụng phải cho IME biết loại nội dung nào chấp nhận và chỉ định phương thức gọi lại được thực thi khi nhận được nội dung.
Ví dụ sau đây minh hoạ cách tạo EditText
chấp nhận hình ảnh 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; } };
Sau đây là nội dung giải thích thêm:
Ví dụ này sử dụng Thư viện hỗ trợ, vì vậy, sẽ có một số tệp tham chiếu đến
android.support.v13.view.inputmethod
thay vìandroid.view.inputmethod
.Ví dụ này sẽ tạo một
EditText
và ghi đè phương thứconCreateInputConnection(EditorInfo)
để sửa đổiInputConnection
.InputConnection
là kênh liên lạc giữa IME và ứng dụng đang nhận dữ liệu đầu vào.Lệnh gọi
super.onCreateInputConnection()
duy trì hành vi tích hợp sẵn (gửi và nhận văn bản) đồng thời cung cấp cho bạn thông tin tham chiếu đếnInputConnection
.setContentMimeTypes()
thêm danh sách các loại MIME được hỗ trợ vàoEditorInfo
. Hãy gọisuper.onCreateInputConnection()
trướcsetContentMimeTypes()
.callback
được thực thi bất cứ khi nào IME gửi nội dung. Phương thứconCommitContent()
có tham chiếu đếnInputContentInfoCompat
, chứa một URI nội dung.- Yêu cầu và huỷ bỏ quyền nếu ứng dụng của bạn đang chạy trên API cấp 25 trở lên và cờ
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
là do IME đặt. Nếu không, bạn đã có quyền truy cập vào URI nội dung vì yêu cầu này được IME cấp hoặc vì trình cung cấp nội dung không hạn chế quyền truy cập. Để biết thêm thông tin, hãy xem phần Thêm tính năng hỗ trợ hình ảnh vào IME.
- Yêu cầu và huỷ bỏ quyền nếu ứng dụng của bạn đang chạy trên API cấp 25 trở lên và cờ
createWrapper()
sẽ góiInputConnection
,EditorInfo
đã sửa đổi và lệnh gọi lại vào mộtInputConnection
mới rồi trả về đối tượng đó.
Sau đây là các phương pháp được đề xuất:
Những trình chỉnh sửa không hỗ trợ nội dung đa dạng thức sẽ không gọi hàm
setContentMimeTypes()
và họ đểEditorInfo.contentMimeTypes
được đặt thànhnull
.Trình chỉnh sửa sẽ bỏ qua nội dung nếu loại MIME được chỉ định trong
InputContentInfo
không khớp với bất kỳ loại nào mà họ chấp nhận.Nội dung đa dạng thức không ảnh hưởng và không bị ảnh hưởng bởi vị trí của con trỏ văn bản. Trình chỉnh sửa có thể bỏ qua vị trí con trỏ khi làm việc với nội dung.
Trong phương thức
OnCommitContentListener.onCommitContent()
của trình chỉnh sửa, bạn có thể trả vềtrue
không đồng bộ, ngay cả trước khi tải nội dung.Không giống như văn bản (có thể chỉnh sửa được trong IME trước khi gửi), nội dung đa dạng thức sẽ được xác nhận ngay lập tức. Nếu bạn muốn cho phép người dùng chỉnh sửa hoặc xoá nội dung, hãy tự triển khai logic.
Để kiểm thử ứng dụng, hãy đảm bảo thiết bị hoặc trình mô phỏng của bạn có bàn phím có thể gửi nội dung đa dạng thức. Bạn có thể sử dụng Bàn phím Google trong Android 7.1 trở lên.
Thêm tính năng hỗ trợ hình ảnh vào IME
Các IME muốn gửi nội dung đa dạng thức tới ứng dụng phải triển khai Commit Content API, như trong ví dụ sau:
- Ghi đè
onStartInput()
hoặconStartInputView()
và đọc danh sách các loại nội dung được hỗ trợ của trình chỉnh sửa mục tiêu. Đoạn mã sau đây cho biết cách kiểm tra xem trình chỉnh sửa mục tiêu có chấp nhận hình ảnh GIF hay không.
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. } }
- Gửi nội dung cho ứng dụng khi người dùng chọn một hình ảnh. Tránh gọi
commitContent()
khi có bất kỳ văn bản nào đang được soạn, vì điều này có thể khiến trình chỉnh sửa mất tiêu điểm. Đoạn mã sau đây cho biết cách cam kết hình ảnh 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); }
Là một tác giả IME, rất có thể bạn phải triển khai trình cung cấp nội dung của riêng mình để phản hồi các yêu cầu URI nội dung. Trường hợp ngoại lệ là nếu IME của bạn hỗ trợ nội dung của các trình cung cấp nội dung hiện có như MediaStore
. Để biết thông tin về trình cung cấp nội dung xây dựng, hãy xem tài liệu về trình cung cấp nội dung và trình cung cấp tệp.
Nếu đang xây dựng trình cung cấp nội dung của riêng mình, bạn không nên xuất trình cung cấp đó bằng cách đặt android:exported
thành false
. Thay vào đó, hãy bật tính năng cấp quyền trong trình cung cấp bằng cách đặt android:grantUriPermission
thành true
. Sau đó, IME của bạn có thể cấp quyền truy cập URI nội dung khi
nội dung được gửi. Có 2 cách để thực hiện việc này:
Trên Android 7.1 (API cấp 25) trở lên, khi gọi
commitContent()
, hãy đặt tham số gắn cờ thànhINPUT_CONTENT_GRANT_READ_URI_PERMISSION
. Sau đó, đối tượngInputContentInfo
mà ứng dụng nhận được có thể yêu cầu và giải phóng quyền đọc tạm thời bằng cách gọirequestPermission()
vàreleasePermission()
.Trên Android 7.0 (API cấp 24) trở xuống,
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
sẽ bị bỏ qua, vì vậy, hãy cấp quyền cho nội dung theo cách thủ công. Có một cách để thực hiện việc này là sử dụnggrantUriPermission()
, nhưng bạn có thể triển khai cơ chế riêng đáp ứng các yêu cầu của riêng mình.
Để kiểm tra IME, hãy đảm bảo thiết bị hoặc trình mô phỏng của bạn có một ứng dụng có thể nhận nội dung đa dạng thức. Bạn có thể sử dụng ứng dụng Google Messenger trên Android 7.1 trở lên.