Come sviluppatore di app so che convincere gli utenti a continuare a usare la tua app è una delle problematiche più grandi. Anche se le notifiche a livello di sistema operativo sono un ottimo modo per ricordare agli utenti di ritornare alla tua app, possono perdersi nel mare di notifiche inviate dalle altre app. Ad esempio, se vuoi comunicare ai clienti qualche power-up in vendita nel tuo store in-app, non sarebbe meglio parlarne quando avviano il gioco o completano un livello piuttosto che quando stanno andando al lavoro?
Considerando ciò, abbiamo rilasciato recentemente un ottimo prodotto per promuovere e far crescere la tua app: Firebase In-App Messaging. Grazie a In-App Messaging, ora puoi coinvolgere gli utenti che utilizzano attivamente la tua app iOS o Android inviando loro messaggi mirati, personalizzati e contestuali. Queste notifiche indirizzano gli utenti verso importanti azioni in-app, come iscriversi alla newsletter, guardare un video o acquistare un prodotto.
Ora hai la flessibilità e il controllo di impostare messaggi in-app in una varietà di formati e attivarli in base al comportamento degli utenti. Illustrerò solo un esempio dei numerosi modi di utilizzare Firebase In-App Messaging. Ho già configurato la mia app in modo che possa ricevere messaggi seguendo le istruzioni contenute nella Guida introduttiva.
Supponiamo di avere un'app per social media basata sulla pubblicazione di foto di gatti. Di recente ho lanciato una nuova funzione di condivisione che voglio comunicare ai miei utenti.
Quindi questo è un perfetto caso d'uso per Firebase In-App Messaging. Grazie a Firebase In-App Messaging, posso creare la campagna direttamente dalla Console Firebase, come indicato qui sotto.
Nella console, ho scelto un'immagine e un colore del pulsante che rispecchino il look e lo stile della mia app. Ho anche incluso un'azione del pulsante che nel mio caso farà visualizzare la finestra di dialogo di condivisione nell'app, in modo che gli utenti possano condividere facilmente le loro foto preferite.
In-App Messaging offre molte opzioni di targeting dei messaggi che ti consentono di adattare i messaggi in base ai gruppi che desideri raggiungere. Puoi selezionare tutti gli utenti dell'app, gli utenti di segmenti di pubblico specifici di Google Analytics, gli utenti che corrispondono a determinate proprietà o gli utenti che Firebase Predictions prevede che aderiranno a una determinata iniziativa nei prossimi sette giorni. Nel mio caso, seleziono tutti gli utenti.
Con la funzione di pianificazione, posso decidere quando questa finestra di dialogo verrà visualizzata nell'app. Potrei usare Firebase In-App Messaging per mostrare un messaggio ai miei utenti quando avviano l'app per la prima volta, ma voglio che la mia campagna sia più mirata e pertinente, quindi decido di mostrare il messaggio solo agli utenti che mettono Mi piace (o "zampa su") alla loro prima foto.
Ho anche la possibilità di impostare una data di inizio e di fine per la mia campagna, se mai dovessi organizzare una promozione stagionale.
Infine, posso selezionare un evento di conversione, ossia il parametro che misura se la campagna ha avuto successo. Nel mio caso, terrò traccia degli utenti che hanno condiviso o meno un'immagine.
L'evento di conversione scelto viene tracciato nella Console Firebase, come indicato nel grafico.
Per tutta la durata della campagna posso tenere traccia di impressioni, clic su pulsanti e conversioni. Posso anche modificare la campagna, e ciò mi permette di testare le modifiche che potrebbero migliorare il tasso di conversione.
Questo è solo un esempio di come In-App Messaging aiuta a promuovere la conversione. Può anche essere utilizzato per mettere in evidenza una vendita o un coupon all'interno di un'app e-commerce, informare gli utenti dei termini di aggiornamento del servizio o mostrare nuove funzionalità. All'interno dell'app, Firebase In-App Messaging rappresenta una sorta di guida che incoraggia l'esplorazione e la scoperta delle app, incrementa la durata delle sessioni e favorisce le conversioni. Per ulteriori esempi, vai a vedere il nostro annuncio sul blog!
Pronto per un'immersione totale? Inizia oggi stesso consultando la documentazione.
Getting started with Firebase In-App Messaging
Hai un caso d'uso perfetto per Firebase In-App Messaging? Condividilo con me su Twitter @ThatJenPerson. Non vedo l’ora di scoprire cosa riuscirai a creare!
Come abbiamo già accennato a maggio, le persone creano e utilizzano foto e video in molti modi diversi, quindi sosteniamo che sfruttarli meglio e farci ancora di più dovrebbe essere più semplice nell'ambito dei molti dispositivi e app che usiamo sempre. Ecco perché abbiamo prodotto l'API Google Photos Library, che offre la possibilità di creare esperienze di foto e video più intelligenti, veloci e utili all'interno dei tuoi prodotti.
Dopo un'anteprima di sviluppo ben accolta negli ultimi mesi, l'API Google Photos Library è ora disponibile per il pubblico. Se vuoi creare e testare la tua esperienza, inizia visitando la documentazione per sviluppatori. Puoi anche esprimere il tuo interesse aderendo al programma partner di Google Foto se stai pianificando un'integrazione più ampia.
Ecco una rapida panoramica dell'API Google Photos Library e come utilizzarla.
Sia che tu sia uno sviluppatore mobile, web o di backend, puoi utilizzare questa API REST per sfruttare il meglio di Google Foto e aiutare le persone a connettersi, caricare e condividere all'interno della tua app. Stiamo anche lanciando librerie client in diverse lingue che ti consentiranno di procedere più rapidamente.
Gli utenti devono autorizzare le richieste tramite l'API, in tal modo sono sempre al comando della situazione. Ecco cosa puoi aiutarli a fare:
Sfruttare il machine learning a vantaggio della tua app è semplice. Puoi utilizzare i filtri intelligenti, come le categorie di contenuti, per limitare o escludere determinati tipi di foto o video, e aiutare gli utenti a trovare più facilmente ciò che stanno cercando.
Ringraziamo tutti coloro che ci hanno fornito il loro feedback durante l'anteprima degli sviluppatori. Tutti i commenti ricevuti hanno contribuito a migliorare l'API. Sono disponibili le note sulla versione che accompagnano le nuove release della nostra API. Inoltre, se attualmente stai usando l'API Picasa Web Albums, ecco la guida alla migrazione che ti aiuterà a passare all'API Google Photos Library.
Recentemente ho fatto parte del fantastico team che ha lavorato all'app Android Google I/O 2018. È un'app complementare per conferenze che consente ai partecipanti e a chi si trova in remoto di cercare sessioni, creare programmi personalizzati e prenotare posti all'evento (se si ha la fortuna di essere lì!). Nell'app abbiamo sviluppato molte interessanti funzionalità animate che, a mio parere, hanno migliorato notevolmente l'esperienza utente. Il codice di questa app è appena stato reso open source e quindi vorrei segnalare alcuni dettagli e istanze di implementazione interessanti.
Ci sono 3 tipi di animazioni che abbiamo usato maggiormente nell'app:
Mi piacerebbe parlare più nel dettaglio di alcune di queste funzionalità.
Parte della funzione dell'app è creare entusiasmo e attesa per la conferenza. Pertanto, quest'anno abbiamo incluso un grande conto alla rovescia animato per marcare l'inizio della conferenza, visualizzato sia nella schermata di on-boarding sia nella sezione Info. È stata anche un'ottima opportunità per incorporare il marchio dell'evento nell'app dandole così più carattere.
Questa animazione è stata progettata da un motion designer e distribuita come serie di file JSON Lottie: ognuno di 1 secondo che mostra un numero animato in ingresso "in" e in uscita "out". Il formato Lottie ha semplificato il rilascio dei file in asset e ha persino offerto metodi convenienti come setMinAndMaxProgress che ci hanno permesso di riprodurre solo la prima o l'ultima metà di un'animazione (per mostrare un numero animato in ingresso o in uscita).
In generale è stato interessante gestire le varie animazioni del conto alla rovescia. Per ottenere questo obiettivo abbiamo creato una CountdownView personalizzata, che è un ConstraintLayout abbastanza complesso contenente diverse LottieAnimationViews. In questo caso abbiamo creato un delegato Kotlin per incapsulare l'avvio dell'animazione giusta. Ciò ci ha permesso di assegnare semplicemente un Int a ciascun delegato della cifra che doveva essere visualizzata e, a sua volta, il delegato eseguiva l'impostazione e l'avvio delle animazioni. Abbiamo esteso il delegato ObservableProperty per garantire che l'animazione fosse eseguita solo al variare della cifra. Quindi il nostro loop di animazione pubblicava un runnable ogni secondo (quando la visualizzazione era allegata) che calcolava la cifra da mostrare per ogni visualizzazione e poi aggiornava i delegati.
Una delle azioni chiave dell'app è consentire ai partecipanti di prenotarsi. Pertanto abbiamo messo questa azione in evidenza in un FAB nella schermata dei dettagli della sessione. Abbiamo ritenuto importante segnalare solamente che la sessione era stata riservata, una volta che l'operazione veniva completata correttamente sul backend (a differenza delle azioni meno importanti, come la valutazione di una sessione, per cui ottimisticamente l'UI veniva aggiornata subito). Ricevere una risposta dal backend poteva richiedere tempo quindi, per rendere il processo più dinamico, abbiamo creato un'icona animata per indicare che il processo è in corso e passare agevolmente al nuovo stato.
Il processo è complicato dal fatto che questa icona rappresenta diversi stati: la sessione che può essere prenotata, l'utente che può aver già prenotato, se la sessione è esaurita potrebbe essere disponibile una lista d'attesa o l’utente potrebbe essere già sulla lista d'attesa o, con l’avvicinarsi della sessione, le prenotazioni potrebbero non essere più disponibili. Ciò dà luogo a molte transizioni di stato da animare. Per semplificare queste transizioni, abbiamo deciso di passare sempre attraverso uno stato "in corso", ossia la clessidra animata mostrata sopra. Pertanto ogni transizione è costituita da una coppia di stati: stato 1 → in corso e in corso → stato 2. Questo approccio ha semplificato moltissimo le cose. Abbiamo creato ognuna di queste animazioni usando shapeshifter; vedi i file avd_state_to_state qui.
Per mostrare ciò, abbiamo utilizzato una visualizzazione personalizzata AnimatedStateListDrawable (ASLD). Se non hai mai usato ASLD, si tratta di una versione animata di StateListDrawable, come suggerisce il nome, che hai probabilmente già visto e consente, non solo di fornire diverse risorse drawable per stato ma anche transizioni tra stati (sotto forma di AnimatedVectorDrawable o AnimationDrawable). Ecco la risorsa drawable che definisce le immagini statiche e le transizioni in ingresso e uscita dello stato "in corso" per l'icona della prenotazione.
Abbiamo creato una visualizzazione personalizzata per supportare i nostri stati personalizzati. Le visualizzazioni offrono alcuni stati standard come Premuto o Selezionato. Analogamente, puoi definire il tuo stato e avere il Percorso di visualizzazione a tutte le risorse drawable mostrate. Abbiamo definito gli state_reservable, state_reserved ecc. Poi abbiamo creato un Enum dei diversi stati incapsulando lo stato della visualizzazione più eventuali attributi correlati, come la descrizione dei contenuti associati. La nostra logica business potrebbe semplicemente impostare il valore appropriato dall'Enum alla visualizzazione (tramite associazione dati) aggiornando lo stato della risorsa drawable che, a sua volta, ha avviato l'animazione tramite ASLD. La combinazione degli stati personalizzati e AnimatedStateListDrawable è stata un ottimo modo per implementare questo processo, mantenendo i diversi stati ai livelli dichiarativi e dando luogo a un codice di visualizzazione minimo.
Molte transizioni dello schermo funzionavano bene con le animazioni nelle finestre standard. La situazione era un po' diversa per la transizione nella schermata dei dettagli del relatore. Mostrava l'immagine dei relatori da entrambi i lati della transizione ed era una soluzione ideale per transizioni di elementi condivisi perché facilitava il cambio di contesto tra schermate.
Si tratta di una transizione di elementi condivisi standard che utilizza le classi ChangeBounds e ArcMotion della piattaforma su un ImageView.
L’aspetto più interessante è il modo in cui l'avvio di questa transizione si adattava al pattern Evento usato per la navigazione. In sostanza, questo pattern disaccoppia gli eventi di input (come l'azione di tocco di un relatore) dagli eventi di navigazione, incaricando ViewModel di rispondere all'input. In questo caso, il disaccoppiamento implicava che ViewModel esponesse un LiveData degli Eventi, che conosceva solo l'ID del relatore a cui indirizzarsi. L’inizializzazione di una transizione condivisa di elementi richiede la Visualizzazione condivisa che non avevamo a questo punto. Abbiamo risolto il problema memorizzando l'ID del relatore come tag sulla visualizzazione quando è associato, in modo che possa essere recuperato in un secondo momento per navigare verso una particolare schermata dei dettagli del relatore.
Una parte fondamentale dell'app per conferenze è filtrare gli eventi a cui siamo interessati. Ogni argomento viene associato a un colore per essere riconosciuto facilmente. Abbiamo anche ottenuto un ottimo design per il "chip" personalizzato da utilizzare per la selezione dei filtri.
Abbiamo preso in considerazione Chip di Material Components ma poi abbiamo optato per la nostra visualizzazione personalizzata che offriva un maggiore controllo sul display e sull'animazione tra i vari stati "selezionati". È stata implementata usando il disegno su canvas e uno StaticLayout per la visualizzazione del testo. La visualizzazione ha una singola proprietà di avanzamento [0-1] che indica la modalità selezionata-deselezionata. Per cambiare lo stato, il valore viene animato e la visualizzazione viene invalidata, consentendo al codice di rendering di interpolare linearmente le posizioni e le dimensioni degli elementi in base a ciò.
Inizialmente, durante l'implementazione, ho fatto in modo che la visualizzazione implementasse l'interfaccia Checkable e ho avviato l'animazione quando il metodo setChecked impostava un nuovo stato. Poiché si visualizzavano più filtri in un RecyclerView, ciò ha avuto lo sfortunato effetto di eseguire l'animazione se il filtro selezionato si spostava "out" e la visualizzazione veniva riassociata a un filtro non selezionato che si era spostato "in". Ops. Abbiamo quindi aggiunto un altro metodo per avviare l'animazione che ci permettesse di distinguere tra l'attivazione da clic e l'aggiornamento immediato quando si associavano nuovi dati alla visualizzazione.
Inoltre, quando abbiamo introdotto questa animazione toggle, abbiamo scoperto che si trattava di una procedura di janking, ovvero che comportava la perdita di fotogrammi. Era colpa del mio codice di animazione? Questi filtri sono visualizzati in un BottomSheet davanti alla schermata del programma principale della conferenza. Attivando un filtro, avviamo la logica del filtro da applicare al programma (e aggiorniamo il numero di eventi corrispondenti nel titolo del foglio del filtro). Dopo un'analisi approfondita di systrace abbiamo individuato il problema, ossia che quando i filtri venivano applicati, il ViewPager di RecyclerViews, che mostrava il programma diligentemente, si attivava e aggiornava in base ai dati appena forniti. Ciò determinava l'ingrandimento e l'associazione di diverse visualizzazioni. Tutto questo lavoro stava facendo saltare il budget dei fotogrammi... ma il programma di aggiornamento non era visibile perché era nascosto dal foglio del filtro. Abbiamo deciso di ritardare l'utilizzo del filtro vero e proprio fino a quando non veniva eseguita l'animazione, e quindi abbiamo rinunciato a una maggiore complessità di implementazione a favore di un'esperienza utente più fluida. Inizialmente ho implementato questa funzionalità usando PostDelayed ma ciò ha causato problemi durante i test dell'UI. Invece abbiamo cambiato il metodo che ha avviato l'animazione per accettare un lambda da eseguire alla fine. Ciò ci ha permesso di rispettare meglio le impostazioni di animazione dell'utente e testare correttamente l'esecuzione.
Nel complesso, penso che le animazioni abbiano davvero contribuito all'esperienza, al carattere, al branding e alla reattività dell'app. Speriamo che questo post abbia contribuito a spiegare sia il motivo sia il metodo utilizzati, e a fornirti buone indicazioni su come implementare le animazioni.
Animazione in un programma è stato originariamente pubblicato su Android Developers del blog Medium, utile per continuare la conversazione e offrire feedback su questa storia.
Attualmente Crashlytics elabora più di 3 miliardi di eventi al giorno per i nostri sviluppatori e li distilla in una serie di problemi strategici e actionable nel dashboard. Nel corso degli anni abbiamo ricevuto migliaia di richieste relative a come conoscere meglio i dati di arresto anomalo, ed è per questo che ora siamo particolarmente lieti di offrirti la possibilità di esportare i dati Firebase Crashlytics in BigQuery per un'analisi più approfondita!
Con pochi clic nel dashboard di Firebase Crashlytics puoi abilitare le esportazioni giornaliere di tutti i dati raw di arresto anomalo in base all'app o al progetto. Ciò include le tracce dello stack, i registri, le chiavi e qualsiasi altro dato di arresto anomalo.
Il dashboard Crashlytics conserva i dati per 90 giorni. Con BigQuery possiedi le politiche di conservazione e cancellazione che consentono al tuo team di monitorare più facilmente le tendenze dei dati di stabilità anno dopo anno.
BigQuery offre anche la possibilità di esportare dati in formato CSV, JSON e Avro. Ciò contribuirà a semplificare qualsiasi richiesta di estrazione dati GDPR che potresti ricevere.
Fino a ora, la visibilità nei report sugli arresti anomali tramite metadati personalizzati, come Experiment ID o un breadcrumb Analytics, è stata limitata, rendendo difficile l'identificazione delle varianti con minore stabilità in un esperimento o il livello di gioco con il maggior numero di arresti anomali. Ora, quando esporti i dati in BigQuery, è facile eseguire tutte le analisi approfondite che desideri per poi visualizzare il report con Data Studio o qualsiasi altro sistema aziendale utilizzato.
Ad esempio, supponi di configurare il tuo gioco Android in modo da poter registrare a quale livello avviene l'arresto anomalo con:
Crashlytics.setInt("current_level", 3);
Quando esporti i tuoi dati Crashlytics in BigQuery, puoi visualizzare la distribuzione degli arresti anomali per livello grazie a questa query:
#standardSQL SELECT COUNT(DISTINCT event_id) AS num_of_crashes, value FROM `projectId.crashlytics.package_name_ANDROID`, UNNEST(custom_keys) WHERE key = "current_level" GROUP BY key, value ORDER BY num_of_crashes DESC
Se sei già un utente Fabric, puoi accedere all'esportazione BigQuery e a tutte le altre funzionalità di Firebase, collegando la tua app al dashboard Fabric. Dai un'occhiata a questo link per scoprire ulteriori dettagli e consultare la documentazione.
Speriamo che questo miglioramento renda ancora più facile l'accesso ai dati dei tuoi report sugli arresti anomali e al debugging efficace della tua app! Come sempre, se hai domande, puoi trovarci su Twitter e su Stack Overflow. Buon debugging!