Unterstützung für Bildtastatur

Nutzer möchten oft über Emojis, Sticker und andere Arten von Inhalten kommunizieren. In früheren Android-Versionen konnten über Softtastaturen, auch als Eingabemethoden-Editoren oder IMEs bezeichnet, nur Unicode-Emojis an Apps gesendet werden. Für Rich-Inhalte wurden in den Apps appspezifische APIs erstellt, die nicht in anderen Apps verwendet werden konnten, oder Behelfslösungen wie das Senden von Bildern über eine einfache Freigabeaktion oder die Zwischenablage verwendet.

Ein Bild mit einer Tastatur, die die Bildersuche unterstützt
Abbildung 1: Beispiel für die Unterstützung von Bildtastaturen.

Ab Android 7.1 (API-Ebene 25) enthält das Android SDK die Commit Content API. Damit können IMEs Bilder und andere Rich Content direkt an einen Texteditor in einer App senden. Die API ist auch in der Supportbibliothek von Version 13 ab Version 25.0.0 verfügbar. Wir empfehlen die Verwendung der Supportbibliothek, da sie Hilfsmethoden enthält, die die Implementierung vereinfachen.

Mit dieser API können Sie Messaging-Apps erstellen, die Rich-Content von jeder Tastatur sowie Tastaturen zulassen, die Rich-Content an jede App senden können. Die Google-Tastatur und Apps wie Messages von Google unterstützen die Commit Content API in Android 7.1 (siehe Abbildung 1).

In diesem Dokument wird beschrieben, wie die Commit Content API sowohl in IMEs als auch in Anwendungen implementiert wird.

So funktionierts

Das Einfügen von Tastaturbildern erfordert eine Beteiligung des IME und der Anwendung. In der folgenden Reihenfolge werden die einzelnen Schritte des Bildeinfügevorgangs beschrieben:

  1. Wenn der Nutzer auf ein EditText tippt, sendet der Editor eine Liste von MIME-Inhaltstypen, die in EditorInfo.contentMimeTypes akzeptiert werden.

  2. Der IME liest die Liste der unterstützten Typen und zeigt auf der Softtastatur Inhalte an, die der Editor akzeptieren kann.

  3. Wenn der Nutzer ein Bild auswählt, ruft der IME commitContent() auf und sendet ein InputContentInfo-Element an den Editor. Der commitContent()-Aufruf entspricht dem commitText()-Aufruf, allerdings für Rich Content. InputContentInfo enthält einen URI, der den Inhalt eines Contentanbieters identifiziert.

Dieser Prozess wird in Abbildung 2 dargestellt:

Ein Bild, das die Abfolge von der Anwendung zum IME und zurück zur Anwendung zeigt
Abbildung 2. Ablauf von Anwendung zu IME und Anwendung

Bildunterstützung zu Apps hinzufügen

Um Rich Content von IMEs zu akzeptieren, muss eine App den IMEs mitteilen, welche Inhaltstypen akzeptiert werden, und eine Callback-Methode angeben, die beim Empfang von Inhalten ausgeführt wird. Das folgende Beispiel zeigt, wie Sie ein EditText erstellen, das PNG-Bilder akzeptiert:

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;
    }
};

Im Folgenden finden Sie weitere Erläuterungen:

  • In diesem Beispiel wird die Supportbibliothek verwendet. Daher gibt es einige Verweise auf android.support.v13.view.inputmethod anstelle von android.view.inputmethod.

  • In diesem Beispiel wird ein EditText erstellt und seine Methode onCreateInputConnection(EditorInfo) überschrieben, um den InputConnection zu ändern. Der InputConnection ist der Kommunikationskanal zwischen einem IME und der Anwendung, die ihre Eingabe empfängt.

  • Durch den Aufruf super.onCreateInputConnection() wird das integrierte Verhalten beibehalten, d. h. Text wird gesendet und empfangen und es wird auf InputConnection verwiesen.

  • setContentMimeTypes() fügt dem EditorInfo eine Liste der unterstützten MIME-Typen hinzu. Rufen Sie super.onCreateInputConnection() vor dem setContentMimeTypes() auf.

  • callback wird immer dann ausgeführt, wenn der IME einen Commit für Inhalte durchführt. Die Methode onCommitContent() verweist auf InputContentInfoCompat, das einen Inhalts-URI enthält.

    • Fordern Sie Berechtigungen an und geben Sie Berechtigungen frei, wenn Ihre App auf API-Level 25 oder höher ausgeführt wird und das Flag INPUT_CONTENT_GRANT_READ_URI_PERMISSION vom IME festgelegt wird. Andernfalls haben Sie bereits Zugriff auf den Inhalts-URI, da er vom IME gewährt wird oder der Contentanbieter den Zugriff nicht einschränkt. Weitere Informationen finden Sie unter Image-Unterstützung zu IMEIs hinzufügen.
  • createWrapper() fasst die InputConnection, die geänderte EditorInfo und den Callback in eine neue InputConnection zusammen und gibt sie zurück.

Wir empfehlen folgende Vorgehensweisen:

  • Editoren, die Rich-Content nicht unterstützen, rufen setContentMimeTypes() nicht auf und lassen EditorInfo.contentMimeTypes auf null festgelegt.

  • Bearbeiter ignorieren den Inhalt, wenn der in InputContentInfo angegebene MIME-Typ mit keinem der akzeptierten Typen übereinstimmt.

  • Rich Content wirkt sich nicht auf die Position des Textcursors aus und wird auch nicht durch diese beeinflusst. Bearbeiter können die Cursorposition beim Arbeiten mit Inhalten ignorieren.

  • In der Methode OnCommitContentListener.onCommitContent() des Editors können Sie true asynchron zurückgeben, noch bevor der Inhalt geladen wird.

  • Im Gegensatz zu Text, der vor dem Commit im IME bearbeitet werden kann, wird bei Rich Content sofort ein Commit durchgeführt. Wenn Sie möchten, dass Nutzer Inhalte bearbeiten oder löschen, implementieren Sie die Logik selbst.

Zum Testen Ihrer App muss Ihr Gerät oder Emulator eine Tastatur haben, die Rich-Content senden kann. Sie können die Google-Tastatur unter Android 7.1 oder höher verwenden.

Image-Unterstützung zu IMEs hinzufügen

IMEs, die Rich Content an Anwendungen senden möchten, müssen die Commit Content API implementieren, wie im folgenden Beispiel gezeigt:

  • Überschreiben Sie onStartInput() oder onStartInputView() und lesen Sie die Liste der unterstützten Inhaltstypen aus dem Zieleditor. Das folgende Code-Snippet zeigt, wie geprüft wird, ob der Zieleditor GIF-Bilder akzeptiert.

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.
    }
}

  • Sie können Inhalte an die App übergeben, wenn der Nutzer ein Bild auswählt. Rufen Sie commitContent() nicht auf, wenn Text geschrieben wird, da der Editor sonst möglicherweise den Fokus verliert. Das folgende Code-Snippet zeigt, wie ein Commit für ein GIF-Bild ausgeführt wird.

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);
}

Als IME-Autor müssen Sie wahrscheinlich Ihren eigenen Contentanbieter implementieren, um auf Content-URI-Anfragen zu antworten. Eine Ausnahme gilt, wenn Ihr IME Inhalte vorhandener Contentanbieter wie MediaStore unterstützt. Informationen zum Erstellen von Contentanbietern finden Sie in der Dokumentation zu Contentanbieter und Dateianbieter.

Wenn Sie einen eigenen Contentanbieter erstellen, wird empfohlen, ihn nicht zu exportieren. Dazu setzen Sie android:exported auf false. Aktivieren Sie stattdessen die Gewährung von Berechtigungen beim Anbieter. Setzen Sie dazu android:grantUriPermission auf true. Anschließend kann Ihr IME Berechtigungen für den Zugriff auf den Inhalts-URI gewähren, wenn für den Inhalt ein Commit durchgeführt wird. Dafür gibt es zwei Möglichkeiten:

  • Legen Sie unter Android 7.1 (API-Ebene 25) und höher den Flag-Parameter auf INPUT_CONTENT_GRANT_READ_URI_PERMISSION fest, wenn Sie commitContent() aufrufen. Anschließend kann das InputContentInfo-Objekt, das die App empfängt, temporäre Leseberechtigungen anfordern und freigeben, indem requestPermission() und releasePermission() aufgerufen werden.

  • Unter Android 7.0 (API-Level 24) und niedriger wird INPUT_CONTENT_GRANT_READ_URI_PERMISSION ignoriert. Gewähren Sie in diesem Fall manuell die Berechtigung für den Inhalt. Eine Möglichkeit dazu ist grantUriPermission(). Sie können aber auch einen eigenen Mechanismus implementieren, der Ihre eigenen Anforderungen erfüllt.

Zum Testen des IME muss Ihr Gerät oder Emulator eine App haben, die Rich-Content empfangen kann. Sie können die Google Messenger App unter Android 7.1 oder höher verwenden.