Gli utenti amano immagini, video e altri contenuti espressivi, ma inserire e spostare questi contenuti nelle app non è sempre facile. Per consentire alle app di ricevere più facilmente contenuti avanzati, Android 12 (livello API 31) introduce un'API unificata che consente alla tua app di accettare contenuti da qualsiasi fonte: appunti, tastiera o trascinamento.
Puoi collegare un'interfaccia, ad esempio OnReceiveContentListener
, ai componenti dell'interfaccia utente e ottenere un callback quando i contenuti vengono inseriti tramite qualsiasi meccanismo. Il callback diventa l'unica posizione in cui il tuo codice può gestire la ricezione di tutti i contenuti, dal testo normale e con stile al markup, alle immagini, ai video, ai file audio e altro ancora.
Per garantire la compatibilità con le versioni precedenti di Android, questa API è disponibile anche su AndroidX, a partire da Core 1.7 e Appcompat 1.4, che ti consigliamo di utilizzare durante l'implementazione di questa funzionalità.
Panoramica
Con le altre API esistenti, ogni meccanismo dell'interfaccia utente, come il trascinamento o il menu Tocca e tieni premuto, dispone della propria API corrispondente. Ciò significa che devi eseguire l'integrazione con ogni API separatamente, aggiungendo codice simile per ogni meccanismo che inserisce il contenuto:
L'API OnReceiveContentListener
consolida questi diversi percorsi di codice creando una singola API da implementare, in modo che tu possa concentrarti sulla logica specifica dell'app e lasciare che sia la piattaforma a occuparsi del resto:
Questo approccio implica anche che, quando alla piattaforma vengono aggiunti nuovi modi di inserire contenuti, non è necessario apportare ulteriori modifiche al codice per attivare il supporto nell'app. Se l'app deve implementare la personalizzazione completa per un caso d'uso specifico, puoi comunque utilizzare le API esistenti, che continuano a funzionare allo stesso modo.
Implementazione
L'API è un'interfaccia listener con un singolo metodo,
OnReceiveContentListener
.
Per supportare le versioni precedenti della piattaforma Android, ti consigliamo di utilizzare l'interfaccia OnReceiveContentListener
corrispondente nella libreria AndroidX Core.
Per utilizzare l'API, implementa il listener specificando i tipi di contenuti che l'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 del listener:
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) { Pairsplit = 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 intent, puoi riutilizzare la logica specifica dell'app per gestire gli URI dei contenuti. Restituisci tutti i dati rimanenti per delegare la gestione di questi dati alla piattaforma.
Dopo aver implementato il listener, impostalo sugli elementi UI 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 qualsiasi URI di contenuti nel payload passato a OnReceiveContentListener
.
Normalmente, l'app elabora gli URI dei contenuti in un servizio o in un'attività. Per
l'elaborazione a lunga esecuzione, utilizza
WorkManager. Quando implementi questa funzionalità, estendi le autorizzazioni all'attività o al servizio di destinazione passando i contenuti con 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 dal listener per garantire 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 bypassato.
Se la tua classe View
sostituisce il metodo
onCreateInputConnection
, utilizza l'API Jetpack
InputConnectionCompat.createWrapper
per configurare InputConnection
.
Se la tua 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 tastiera immagine
Puoi considerare l'API OnReceiveContentListener
come la versione successiva
dell'API tastiera immagine esistente. Questa API unificata supporta la funzionalità dell'API tastiera immagine e alcune funzionalità aggiuntive. La compatibilità di dispositivi e funzionalità varia a seconda che utilizzi la libreria Jetpack o le API native dell'SDK Android.
Azione o funzionalità | Supportata dall'API Keyboard image | Supportato da un'API unificata |
---|---|---|
Inserisci dalla tastiera | Sì (livello API 13 e successivi) | Sì (livello API 13 e successivi) |
Inserisci utilizzando Incolla dal menu Tocca e tieni premuto | No | Sì |
Inserisci tramite trascinamento | No | Sì (livello API 24 e successivi) |
Azione o funzionalità | Supportata dall'API Keyboard image | Supportato da un'API unificata |
---|---|---|
Inserisci dalla tastiera | Sì (livello API 25 e successivi) | Sì (Android 12 e versioni successive) |
Inserisci utilizzando Incolla dal menu Tocca e tieni premuto | No | |
Inserisci tramite trascinamento | No |