Gli utenti amano le immagini, i video e altri contenuti espressivi, ma inserirli e spostarli nelle app non è sempre facile. Per semplificare il compito delle app di ricevere contenuti avanzati, Android 12 (livello API 31) introduce un'API unificata che consente all'app di accettare contenuti da qualsiasi origine: appunti, tastiera o trascinamento.
Puoi collegare un'interfaccia, ad esempio
OnReceiveContentListener
,
ai componenti dell'interfaccia utente e ricevere un callback quando i contenuti vengono inseriti tramite qualsiasi
meccanismo. Il callback diventa l'unico punto in cui il codice può gestire la ricezione di tutti i contenuti, dal testo normale e con stile al markup, dalle immagini, ai video, ai file audio e ad altri ancora.
Per la compatibilità con le versioni precedenti di Android, questa API è disponibile anche in AndroidX, a partire da Core 1.7 e AppCompat 1.4, che ti consigliamo di utilizzare per implementare questa funzionalità.
Panoramica
Con le altre API esistenti, ogni meccanismo dell'interfaccia utente, ad esempio il menu Tocca e tieni premuto o il trascinamento, ha la propria API corrispondente. Ciò significa che devi eseguire l'integrazione con ogni API separatamente, aggiungendo codice simile per ogni meccanismo che inserisce i contenuti:
L'API OnReceiveContentListener
raggruppa questi diversi percorsi di codice creando un'unica API da implementare, in modo da poterti concentrare sulla logica specifica dell'app e lasciare alla piattaforma il resto:
Questo approccio significa anche che, quando vengono aggiunti nuovi modi per inserire contenuti alla piattaforma, non è necessario apportare ulteriori modifiche al codice per attivare il supporto nella tua app. Inoltre, se la tua app deve implementare una personalizzazione completa per un determinato caso d'uso, puoi comunque utilizzare le API esistenti, che continuano a funzionare allo stesso modo.
Implementazione
L'API è un'interfaccia di listener con un unico metodo,
OnReceiveContentListener
.
Per supportare le versioni precedenti della piattaforma Android, ti consigliamo di utilizzare l'interfaccia corrispondente OnReceiveContentListener
nella libreria AndroidX Core.
Per utilizzare l'API, implementa l'ascoltatore specificando i tipi di contenuti che la tua app può gestire:
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/*"}; // ... }
Dopo aver specificato tutti i tipi MIME dei contenuti supportati dalla tua app, implementa il resto dell'ascoltatore:
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; } }
Se la tua app supporta già la condivisione con gli intent, puoi riutilizzare la logica specifica dell'app per gestire gli URI dei contenuti. Restituire i dati rimanenti per delegare la gestione di questi dati alla piattaforma.
Dopo aver implementato l'ascoltatore, impostalo sugli elementi dell'interfaccia utente appropriati nella tua app:
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()); } }
Autorizzazioni URI
Le autorizzazioni di lettura vengono concesse e rilasciate automaticamente dalla piattaforma per tutti gli
URI dei contenuti nel
payload passato a OnReceiveContentListener
.
In genere, l'app elabora gli URI dei contenuti in un servizio o un'attività. Per l'elaborazione a lunga esecuzione, utilizza WorkManager. Quando implementi questa funzionalità, estendi le autorizzazioni al servizio o all'attività di destinazione passando i contenuti utilizzando Intent.setClipData
e impostando il flag FLAG_GRANT_READ_URI_PERMISSION
.
In alternativa, puoi utilizzare un thread in background nel contesto corrente per elaborare i contenuti. In questo caso, devi mantenere un riferimento all'oggetto payload
ricevuto dall'ascoltatore per assicurarti che le autorizzazioni non vengano revocate prematuramente dalla piattaforma.
Elementi View personalizzati
Se la tua app utilizza una sottoclasse View
personalizzata, assicurati che OnReceiveContentListener
non venga aggirata.
Se la classe View
sostituisce il metodo
onCreateInputConnection
, utilizza l'API Jetpack
InputConnectionCompat.createWrapper
per configurare InputConnection
.
Se la classe View
sostituisce il metodo
onTextContextMenuItem
, delega a super quando la voce di menu è
R.id.paste
o
R.id.pasteAsPlainText
.
Confronto con l'API di immagini della tastiera
Puoi considerare l'API OnReceiveContentListener
come la versione successiva dell'API di immagini della tastiera esistente. Questa API unificata supporta le funzionalità dell'API di immagini della tastiera, oltre ad alcune funzionalità aggiuntive. La compatibilità con i dispositivi e le funzionalità varia a seconda che tu utilizzi la libreria Jetpack o le API native dell'SDK Android.
Azione o funzionalità | Supportato dall'API di immagini della tastiera | Supportato dall'API unificata |
---|---|---|
Inserire dalla tastiera | Sì (livello API 13 e versioni successive) | Sì (livello API 13 e versioni successive) |
Inserire utilizzando l'opzione Incolla dal menu Tocca e tieni premuto | No | Sì |
Inserire gli elementi utilizzando il trascinamento | No | Sì (livello API 24 e versioni successive) |
Azione o funzionalità | Supportato dall'API di immagini della tastiera | Supportato dall'API unificata |
---|---|---|
Inserire dalla tastiera | Sì (livello API 25 e versioni successive) | Sì (Android 12 e versioni successive) |
Inserire utilizzando l'opzione Incolla dal menu Tocca e tieni premuto | No | |
Inserire tramite trascinamento | No |