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. Trong các phiên bản trước của Android, bàn phím mềm (còn được 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 ứng dụng. Đối với nội dung đa dạng thức, các ứng dụng được tạo API dành riêng cho ứng dụng không dùng được trong các ứng dụng khác hoặc đã dùng để giải quyết như gửi hình ảnh thông qua hành động chia sẻ đơn giản hoặc bảng nhớ tạm.
Kể từ Android 7.1 (API cấp 25), SDK Android sẽ bao gồm mã Cam kết Content API cung cấp một cách thức phổ biến để IME gửi hình ảnh và các nội dung đa dạng thức trực tiếp vào trình chỉnh sửa văn bản trong ứng dụng. API này 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 dịch vụ Hỗ trợ Thư viện vì 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 ứng dụng nhắn tin chấp nhận nội dung đa dạng thức từ bất kỳ 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. Nhóm Google Bàn phím và các ứng dụng như Tin nhắn của Google hỗ trợ Commit Content API trong Android 7.1, như được hiển thị 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à của chúng tôi.
Cách hoạt động
Tính năng chèn hình ảnh bàn phím cần có sự tham gia của IME và ứng dụng. Chiến lược phát hành đĩa đơn 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 gửi danh sách các loại nội dung MIME mà trình chỉnh sửa chấp nhậnEditorInfo.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ửi mộtInputContentInfo
cho trình chỉnh sửa. Lệnh gọicommitContent()
tương tự nhưcommitText()
cuộc gọi, nhưng đối với nội dung đa dạng thức.InputContentInfo
chứa một URI xác định nội dung trong một nội dung Google Cloud.
Quá trình này được mô tả trong hình 2:
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 minh hoạ cách tạo EditText
chấp nhận PNG
hình ảnh:
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 cụ thể hơn:
Ví dụ này sử dụng Thư viện hỗ trợ, vì vậy, sẽ có một số 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 đèonCreateInputConnection(EditorInfo)
để sửa đổiInputConnection
.InputConnection
là kênh liên lạc giữa IME và đang nhận đầu vào.Cuộc gọi
super.onCreateInputConnection()
lưu giữ hành vi tích hợp sẵn (gửi và nhận văn bản) và cung cấp cho bạn tham chiếu đếnInputConnection
.setContentMimeTypes()
sẽ thêm danh sách các loại MIME được hỗ trợ vàoEditorInfo
. Gọi điệnsuper.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 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à
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
cờ do IME đặt. Nếu không, bạn đã có quyền truy cập vào nội dung đó URI do IME cấp hoặc do 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 bài viết Thêm 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à
createWrapper()
góiInputConnection
,EditorInfo
đã sửa đổi và lệnh gọi lại vào mộtInputConnection
mới rồi trả lại.
Sau đây là các phương pháp được đề xuất:
Các trình chỉnh sửa không hỗ trợ nội dung đa dạng thức không gọi
setContentMimeTypes()
và họ đểEditorInfo.contentMimeTypes
thiết lập của mình đếnnull
.Trình chỉnh sửa 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 được chấp nhận.Nội dung đa dạng thức không ảnh hưởng và không chịu ảnh hưởng của vị trí của văn bản con trỏ. 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ần trình biên tập
OnCommitContentListener.onCommitContent()
, bạn có thể trả vềtrue
một cách không đồng bộ, thậm chí trước khi tải nội dung.Không giống như văn bản (có thể chỉnh sửa trong IME trước khi gửi ở dạng văn bản đa dạng thức) được cam kết 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á 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
Những IME muốn gửi nội dung đa dạng thức đến ứng dụng phải triển khai Nội dung cam kết như trong ví dụ sau:
- Ghi đè
onStartInput()
hoặconStartInputView()
và đọc danh sách các loại nội dung được hỗ trợ trong mục tiêu trình chỉnh sửa. Đ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. } }
- Xác nhận nội dung cho ứng dụng khi người dùng chọn một hình ảnh. Tránh gọi điện
commitContent()
khi có văn bản đang được soạn vì phần tử này có thể làm cho trình chỉnh sửa mất tiêu điểm. Đoạn mã sau đây cho biết cách xác nhận mộ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à tác giả IME, nhiều khả năng 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
từ các nhà cung cấp nội dung hiện tại như
MediaStore
. Để biết thông tin về
nhà cung cấp nội dung, hãy xem nội dung
nhà cung cấp và tệp
nhà cung cấp của chúng tôi.
Nếu đang xây dựng nhà cung cấp nội dung của riêng mình, bạn không nên xuất nhà cung cấp đó
theo chế độ cài đặt
android:exported
đến
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 cài đặt
android:grantUriPermission
đến 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ó hai 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()
, đặt thông 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à huỷ bỏ 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
bị bỏ qua nên hãy cấp theo cách thủ công quyền đối với nội dung. Một cách để thực hiện việc này là dùnggrantUriPermission()
, nhưng bạn có thể triển khai cơ chế riêng đáp ứng yêu cầu của riêng bạn.
Để kiểm thử IME, hãy đảm bảo thiết bị hoặc trình mô phỏng của bạn có ứ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 trong Android 7.1 trở lên.