รองรับแป้นพิมพ์รูปภาพ

ผู้ใช้มักต้องการสื่อสารโดยใช้อีโมจิ สติกเกอร์ และรูปหลากหลายประเภทอื่นๆ เนื้อหา ใน Android เวอร์ชันก่อนหน้า แป้นพิมพ์เสมือนหรือที่เรียกว่า เครื่องมือแก้ไขวิธีการป้อนข้อมูล หรือ IME - ส่งได้เฉพาะอีโมจิแบบ Unicode ไปยังแอป แอปที่สร้างขึ้นสำหรับเนื้อหาอย่างละเอียด API เฉพาะแอปที่ไม่สามารถใช้ในแอปอื่นหรือใช้วิธีแก้ปัญหาเบื้องต้น เช่น การส่งรูปภาพผ่านการดำเนินการแชร์อย่างง่าย หรือคลิปบอร์ด

วันที่ รูปภาพแสดงแป้นพิมพ์ที่รองรับการค้นหารูปภาพ
รูปที่ 1 ตัวอย่างการรองรับแป้นพิมพ์รูปภาพ

สำหรับ Android SDK ใน Android 7.1 (API ระดับ 25) เป็นต้นไปจะมีสัญญาผูกมัด Content API ซึ่งเป็นวิธีสากลสำหรับ IME ในการส่งรูปภาพและ ข้อมูลอย่างละเอียดไปยังเครื่องมือแก้ไขข้อความในแอปโดยตรง API ยังพร้อมใช้งานใน ไลบรารีการสนับสนุน v13 ณ การแก้ไข 25.0.0 เราขอแนะนำให้ใช้การสนับสนุน ไลบรารีเนื่องจากมีเมธอด Helper ที่ทำให้การใช้งานง่ายขึ้น

คุณสามารถใช้ API นี้สร้างแอปรับส่งข้อความที่ยอมรับข้อมูลอย่างละเอียดจาก แป้นพิมพ์ตลอดจนแป้นพิมพ์ที่สามารถส่งเนื้อหาแบบสมบูรณ์ไปยังแอปพลิเคชันใดก็ได้ แป้นพิมพ์ และแอปอย่าง Messages โดย Google รองรับ Commit Content API ใน Android 7.1 ดังที่แสดงในรูปที่ 1

เอกสารนี้แสดงวิธีใช้ Commit Content API ทั้งใน IME และ แอป

วิธีการทำงาน

การแทรกรูปภาพแป้นพิมพ์ต้องมีการมีส่วนร่วมจาก IME และแอป ลำดับต่อไปนี้จะอธิบายแต่ละขั้นตอนในกระบวนการแทรกรูปภาพ

  1. เมื่อผู้ใช้แตะ EditText เครื่องมือแก้ไขจะส่งรายการประเภทเนื้อหา MIME ที่ยอมรับ EditorInfo.contentMimeTypes

  2. IME จะอ่านรายการประเภทที่สนับสนุนและแสดงเนื้อหาในตัวเลือก แป้นพิมพ์ที่โปรแกรมแก้ไขสามารถยอมรับได้

  3. เมื่อผู้ใช้เลือกรูปภาพ หมายเลข IME จะเรียกใช้ commitContent() และส่ง InputContentInfo กับเอดิเตอร์เท่านั้น การเรียก commitContent() คล้ายกับการเรียก commitText() แต่ใช้เรียกเนื้อหาอย่างละเอียด InputContentInfo มี URI ที่ ระบุเนื้อหาในเนื้อหา เป็นผู้ให้บริการคลาวด์

กระบวนการนี้แสดงอยู่ในรูปที่ 2

วันที่ รูปภาพแสดงลำดับจากแอปพลิเคชันไปยัง IME และกลับไปที่แอปพลิเคชัน
รูปที่ 2 การสมัครไปยัง IME เพื่อดำเนินการตามกระบวนการสมัคร

เพิ่มการรองรับรูปภาพในแอป

ในการยอมรับข้อมูลอย่างละเอียดจาก IME แอปจะต้องบอก IME ว่าเนื้อหาประเภทใด ยอมรับและระบุเมธอด Callback ที่จะทำงานเมื่อได้รับเนื้อหา ตัวอย่างต่อไปนี้แสดงวิธีการสร้าง 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 หรือสูงกว่า และ INPUT_CONTENT_GRANT_READ_URI_PERMISSION ซึ่ง IME จะเป็นผู้กำหนดธง ไม่เช่นนั้น คุณจะมีสิทธิ์เข้าถึงเนื้อหาอยู่แล้ว URI เนื่องจากได้มาจาก IME หรือเนื่องจากผู้ให้บริการเนื้อหา ไม่ได้จำกัดการเข้าถึง สำหรับข้อมูลเพิ่มเติม โปรดดูที่เพิ่มการสนับสนุนรูปภาพไปยัง IME
  • createWrapper() รวม InputConnection, EditorInfo ที่แก้ไข และ Callback ลงใน InputConnection ใหม่และส่งคืน

แนวทางปฏิบัติที่แนะนำมีดังนี้

  • ผู้แก้ไขที่ไม่สนับสนุนข้อมูลอย่างละเอียดจะไม่เรียกใช้ setContentMimeTypes() และสมาชิกออกจากการตั้งค่า EditorInfo.contentMimeTypes แล้ว ไปยัง null

  • เอดิเตอร์จะไม่สนใจเนื้อหาหากประเภท MIME ที่ระบุไว้ใน InputContentInfo ไม่ตรงกับประเภทใดๆ ที่พวกเขายอมรับ

  • ข้อมูลอย่างละเอียดไม่มีผลกระทบและไม่ได้รับผลกระทบจากตำแหน่งของข้อความ เคอร์เซอร์ เอดิเตอร์จะเพิกเฉยต่อตำแหน่งเคอร์เซอร์เมื่อทำงานกับเนื้อหาได้

  • ใน OnCommitContentListener.onCommitContent() คุณสามารถแสดงผล true แบบไม่พร้อมกันแม้ ก่อนที่จะโหลดเนื้อหา

  • แตกต่างจากข้อความ ซึ่งแก้ไขได้ใน IME ก่อนที่จะเริ่มต้น เนื้อหานั้นจะตกลงทันที หากต้องการให้ผู้ใช้แก้ไขหรือลบ ให้ใช้ตรรกะด้วยตนเอง

ในการทดสอบแอป โปรดตรวจสอบว่าอุปกรณ์หรือโปรแกรมจำลองมีแป้นพิมพ์ที่ส่ง ข้อมูลอย่างละเอียด คุณสามารถใช้แป้นพิมพ์ของ Google ใน Android 7.1 ขึ้นไป

เพิ่มการรองรับอิมเมจไปยัง IME

IME ที่ต้องการส่ง Rich Content ไปยังแอปต้องใช้ Commit Content API ตามที่แสดงในตัวอย่างต่อไปนี้

  • ลบล้าง onStartInput() หรือ onStartInputView() และอ่านรายการประเภทเนื้อหาที่รองรับจากเป้าหมาย Editor ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีตรวจสอบว่าเป้าหมาย โปรแกรมแก้ไขยอมรับรูปภาพ 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 จากนั้น IME สามารถให้สิทธิ์เข้าถึง URI เนื้อหาเมื่อ เนื้อหาต้องมีการยืนยัน ซึ่งทำได้ 2 วิธีดังนี้

  • ใน Android 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 โปรดตรวจสอบว่าอุปกรณ์หรือโปรแกรมจำลองมีแอปที่รับ ข้อมูลอย่างละเอียด คุณสามารถใช้แอป Google Messenger ได้ใน Android 7.1 ขึ้นไป