Użytkownicy uwielbiają obrazy, filmy i inne treści, ale wstawianie i przenoszenie ich w aplikacjach nie zawsze jest łatwe. Aby ułatwić aplikacjom odbieranie treści multimedialnych, Android 12 (poziom API 31) wprowadza ujednolicony interfejs API, który umożliwia aplikacji akceptowanie treści z dowolnego źródła: schowka, klawiatury lub przeciągania.
Możesz dołączyć interfejs, np. OnReceiveContentListener
, do komponentów interfejsu i otrzymywać wywołanie zwrotne, gdy treści są wstawiane za pomocą dowolnego mechanizmu. Funkcja zwrotna staje się jednym miejscem, w którym kod obsługuje odbieranie wszystkich treści, od zwykłego i sformatowanego tekstu po znaczniki, obrazy, filmy, pliki audio i inne.
Aby zapewnić zgodność wsteczną z poprzednimi wersjami Androida, ten interfejs API jest też dostępny w AndroidX, począwszy od Core 1.7 i Appcompat 1.4. Zalecamy używanie go podczas wdrażania tej funkcji.
Omówienie
W przypadku innych interfejsów API każdy mechanizm interfejsu, np. menu po dotknięciu i przytrzymaniu lub przeciąganie, ma własny interfejs API. Oznacza to, że musisz zintegrować się z każdym interfejsem API osobno, dodając podobny kod dla każdego mechanizmu, który wstawia treści:
Interfejs OnReceiveContentListener
API łączy te różne ścieżki kodu, tworząc jeden interfejs API do wdrożenia, dzięki czemu możesz skupić się na logice specyficznej dla aplikacji, a resztę pozostawić platformie:
Oznacza to również, że gdy na platformie pojawią się nowe sposoby wstawiania treści, nie musisz wprowadzać dodatkowych zmian w kodzie, aby włączyć obsługę w aplikacji. Jeśli aplikacja wymaga pełnego dostosowania do konkretnego przypadku użycia, nadal możesz korzystać z dotychczasowych interfejsów API, które działają w ten sam sposób.
Implementacja
Interfejs API to interfejs detektora z jedną metodą: OnReceiveContentListener
.
Aby obsługiwać starsze wersje platformy Android, zalecamy używanie pasującego interfejsu OnReceiveContentListener
w bibliotece AndroidX Core.
Aby użyć interfejsu API, zaimplementuj odbiornik, określając typy treści, które może obsługiwać Twoja 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, które obsługuje Twoja aplikacja, zaimplementuj pozostałą część odbiornika:
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<ContentInfoCompat, ContentInfoCompat> 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 za pomocą intencji, możesz ponownie wykorzystać logikę aplikacji do obsługi identyfikatorów URI treści. Zwróć wszelkie pozostałe dane, aby przekazać ich obsługę platformie.
Po zaimplementowaniu odbiornika ustaw go w odpowiednich elementach interfejsu w 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 URI
Uprawnienia do odczytu są przyznawane i zwalniane automatycznie przez platformę w przypadku wszystkich identyfikatorów URI treści w ładunku przekazywanym do funkcji OnReceiveContentListener
.
Zwykle aplikacja przetwarza identyfikatory URI treści w usłudze lub aktywności. W przypadku długotrwałego przetwarzania używaj WorkManagera. Gdy to zrobisz, rozszerz uprawnienia na docelową usługę lub aktywność, przekazując treść za pomocą Intent.setClipData
i ustawiając flagę FLAG_GRANT_READ_URI_PERMISSION
.
Możesz też użyć wątku w tle w bieżącym kontekście, aby przetworzyć treść. W takim przypadku musisz zachować odniesienie do obiektu payload
otrzymanego przez odbiorcę, aby mieć pewność, że platforma nie cofnie przedwcześnie uprawnień.
Widoki niestandardowe
Jeśli aplikacja używa niestandardowej klasy podrzędnej View
, upewnij się, że nie jest ona pomijana.OnReceiveContentListener
Jeśli klasa View
zastępuje metodę
onCreateInputConnection
, użyj interfejsu Jetpack API
InputConnectionCompat.createWrapper
do skonfigurowania InputConnection
.
Jeśli klasa View
zastępuje metodę
onTextContextMenuItem
, przekaż wywołanie do klasy nadrzędnej, gdy element menu jest
R.id.paste
lub
R.id.pasteAsPlainText
.
Porównanie z interfejsem API obrazu klawiatury
OnReceiveContentListener
API to nowa wersja dotychczasowego interfejsu API obrazu klawiatury. Ten ujednolicony interfejs API obsługuje funkcje interfejsu API obrazu klawiatury, a także kilka dodatkowych funkcji. Kompatybilność urządzeń i funkcji zależy od tego, czy używasz biblioteki Jetpack czy natywnych interfejsów API z pakietu Android SDK.
Działanie lub funkcja | Obsługiwane przez interfejs API obrazu klawiatury | Obsługiwane przez ujednolicony interfejs API |
---|---|---|
Wstawianie z klawiatury | Tak (poziom API 13 lub wyższy) | Tak (poziom API 13 lub wyższy) |
Wstawianie za pomocą opcji wklejania z menu naciśnięcia i przytrzymania | Nie | Tak |
Wstawianie za pomocą przeciągania i upuszczania | Nie | Tak (poziom interfejsu API 24 lub wyższy) |
Działanie lub funkcja | Obsługiwane przez interfejs API obrazu klawiatury | Obsługiwane przez ujednolicony interfejs API |
---|---|---|
Wstawianie z klawiatury | Tak (poziom API 25 lub wyższy) | Tak (Android 12 lub nowszy) |
Wstawianie za pomocą opcji wklejania z menu naciśnięcia i przytrzymania | Nie | |
Wstawianie metodą „przeciągnij i upuść” | Nie |