Otrzymuj szczegółowe treści

Rysunek 1. Ujednolicony interfejs API zapewnia obsługę przychodzących treści w jednym miejscu niezależnie od konkretnego mechanizmu interfejsu, np. przez wklejanie z poziomu menu „dotknij i przytrzymaj” lub „przeciągnij i upuść”.

Użytkownicy uwielbiają obrazy, filmy i inne ekspresyjne treści, ale umieszczanie ich w aplikacjach i przenoszenie ich w aplikacjach nie zawsze jest łatwe. Aby ułatwić aplikacjom otrzymywanie szczegółowych treści, Android 12 (poziom interfejsu API 31) wprowadza ujednolicony interfejs API, który pozwala aplikacji akceptować treści z dowolnego źródła: ze schowka, klawiatury czy przeciągania.

Do komponentów UI możesz dołączyć interfejs, na przykład OnReceiveContentListener, i otrzymać wywołanie zwrotne, gdy treść zostanie wstawiona za pomocą dowolnego mechanizmu. Wywołanie zwrotne staje się jedynym miejscem, w którym kod może odbierać wszystkie treści – od zwykłego tekstu i ze stylem po znaczniki, obrazy, filmy, pliki audio i inne.

Aby zapewnić zgodność wsteczną z poprzednimi wersjami Androida, ten interfejs API jest też dostępny w AndroidzieX od Core 1.7 do Appcompat 1.4. Zalecamy korzystanie z tej funkcji podczas wdrażania tej funkcji.

Przegląd

W przypadku innych istniejących interfejsów API każdy mechanizm interfejsu – np. menu dotknięcia i przytrzymania czy przeciąganie – ma własny interfejs API. Oznacza to, że musisz przeprowadzić integrację z każdym interfejsem API oddzielnie, dodając podobny kod dla każdego mechanizmu, który wstawia treść:

Obraz przedstawiający różne działania i względny interfejs API do zaimplementowania
Rysunek 2. Wcześniej aplikacje implementowały inny interfejs API dla każdego mechanizmu wstawiania treści.

Interfejs OnReceiveContentListener API konsoliduje różne ścieżki kodu, tworząc pojedynczy interfejs API do zaimplementowania. Dzięki temu możesz skupić się na logice związanej z aplikacją, a platformę obsługiwać resztę:

Obraz przedstawiający uproszczony, ujednolicony interfejs API
Rysunek 3. Ujednolicony interfejs API pozwala wdrożyć 1 interfejs API, który obsługuje wszystkie mechanizmy UI.

Oznacza to również, że gdy dodasz do platformy nowe sposoby wstawiania treści, nie musisz wprowadzać dodatkowych zmian w kodzie, aby włączyć obsługę aplikacji. Jeśli aplikacja musi wdrożyć pełne dostosowanie do konkretnego przypadku użycia, możesz nadal korzystać z istniejących interfejsów API, które nadal działają w ten sam sposób.

Implementacja

Interfejs API to interfejs nasłuchującego z pojedynczą metodą – OnReceiveContentListener. Aby obsługiwać starsze wersje platformy Androida, zalecamy skorzystanie z pasującego interfejsu OnReceiveContentListener w bibliotece AndroidX Core.

Aby użyć tego interfejsu API, zaimplementuj detektor, określając typy treści, które może obsługiwać aplikacja:

Kotlin

object MyReceiver : OnReceiveContentListener {
    val MIME_TYPES = arrayOf("image/*", "video/*")
    
    // ...
    
    override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
        TODO("Not yet implemented")
    }
}

Java

public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
     // ...
}

Po określeniu wszystkich typów MIME treści obsługiwanych przez Twoją aplikację zaimplementuj resztę detektora:

Kotlin

class MyReceiver : OnReceiveContentListener {
    override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat {
        val split = contentInfo.partition { item: ClipData.Item -> item.uri != null }
        val uriContent = split.first
        val remaining = split.second
        if (uriContent != null) {
            // App-specific logic to handle the URI(s) in uriContent.
        }
        // Return anything that your app didn't handle. This preserves the
        // default platform behavior for text and anything else that you aren't
        // implementing custom handling for.
        return remaining
    }

    companion object {
        val MIME_TYPES = arrayOf("image/*", "video/*")
    }
}

Java

 public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};

     @Override
     public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) {
         Pair split = contentInfo.partition(
                 item -> item.getUri() != null);
         ContentInfo uriContent = split.first;
         ContentInfo remaining = split.second;
         if (uriContent != null) {
             // App-specific logic to handle the URI(s) in uriContent.
         }
         // Return anything that your app didn't handle. This preserves the
         // default platform behavior for text and anything else that you aren't
         // implementing custom handling for.
         return remaining;
     }
 }

Jeśli Twoja aplikacja obsługuje już udostępnianie z intencjami, możesz ponownie użyć logiki aplikacji do obsługi identyfikatorów URI treści. Zwróć pozostałe dane, aby przekazać obsługę tych danych na platformie.

Po zaimplementowaniu detektora ustaw go w odpowiednich elementach interfejsu aplikacji:

Kotlin

class MyActivity : Activity() {
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        val myInput = findViewById(R.id.my_input)
        ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver())
    }
}

Java

public class MyActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         // ...

         AppCompatEditText myInput = findViewById(R.id.my_input);
         ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver());
     }
}

Uprawnienia dotyczące identyfikatora URI

Platforma automatycznie przyznaje i zwalnia uprawnienia do odczytu w przypadku wszystkich identyfikatorów URI treści w ładunku przekazanym do OnReceiveContentListener.

Normalnie aplikacja przetwarza identyfikatory URI treści w usłudze lub działaniu. Do długotrwałego przetwarzania użyj WorkManagera. Jeśli to zrobisz, rozszerz uprawnienia docelowej usługi lub aktywności, przekazując treści za pomocą Intent.setClipData i ustawiając flagę FLAG_GRANT_READ_URI_PERMISSION.

Do przetwarzania treści możesz też użyć wątku w tle w bieżącym kontekście. W takim przypadku musisz utrzymywać odniesienie do obiektu payload otrzymanego przez detektor, aby zapobiec przedwczesnemu unieważnieniu uprawnień przez platformę.

Widoki niestandardowe

Jeśli Twoja aplikacja używa niestandardowej podklasy View, upewnij się, że nie jest pomijana klasy OnReceiveContentListener.

Jeśli klasa View zastępuje metodę onCreateInputConnection, użyj interfejsu Jetpack API InputConnectionCompat.createWrapper, aby skonfigurować InputConnection.

Jeśli klasa View zastępuje metodę onTextContextMenuItem, przekaż dostęp do super, gdy element menu to R.id.paste lub R.id.pasteAsPlainText.

Porównanie z interfejsem API obrazu klawiatury

Interfejs OnReceiveContentListener API możesz traktować jako nową wersję istniejącego interfejsu Keyboard Image API. Ten ujednolicony interfejs API obsługuje funkcje interfejsu API obrazu klawiatury, a także kilka dodatkowych funkcji. Zgodność urządzenia i funkcji różni się w zależności od tego, czy używasz biblioteki Jetpack, czy natywnych interfejsów API z pakietu Android SDK.

Tabela 1. Obsługiwane funkcje i poziomy interfejsów API Jetpack.
Działanie lub funkcja Obsługiwany przez interfejs API grafiki klawiatury Obsługiwane przez ujednolicony interfejs API
Wstawianie z klawiatury Tak (poziom API 13 lub wyższy) Tak (poziom API 13 lub wyższy)
Wstaw przez wklejenie z menu naciskając i przytrzymując Nie Tak
Wstawianie za pomocą przeciągania i upuszczania Nie Tak (poziom API 24 lub wyższy)
Tabela 2. Obsługiwane funkcje i poziomy interfejsów API w przypadku natywnych interfejsów API.
Działanie lub funkcja Obsługiwany przez interfejs API grafiki klawiatury Obsługiwane przez ujednolicony interfejs API
Wstawianie z klawiatury Tak (poziom API 25 lub wyższy) Tak (Android 12 lub nowszy)
Wstaw przez wklejenie z menu naciskając i przytrzymując Nie
Wstaw za pomocą przeciągania i upuszczania Nie