Plaid consente agli innovatori nello spazio fintech fornendo loro l’accesso ai dati finanziari tramite un’API uniforme. Per aiutare gli utenti finali a collegare i propri dati bancari alle app fintech, Plaid ha sviluppato Link, un modulo drop-in che gestisce la convalida delle credenziali, l’autenticazione a più fattori e la gestione degli errori per ogni banca supportata.
Gli sviluppatori Android in precedenza dovevano aprire gli URL dei collegamenti nelle visualizzazioni Web. Ogni app che voleva utilizzare Link richiedeva un grande sforzo da parte degli sviluppatori e, senza standardizzazione, ci sarebbero stati bug in alcune delle implementazioni. Al fine di migliorare l’esperienza degli sviluppatori, abbiamo recentemente rilasciato un SDK che rende WebView facile da integrare in qualsiasi app con poche righe di codice.
Inoltre, le visualizzazioni Web non sono completamente sicure per gli utenti finali che immettono informazioni sensibili nel flusso di collegamento. Per rendere il nostro SDK il più sicuro possibile, l’abbiamo implementato utilizzando le schede personalizzate di Chrome anziché le WebViews di Android. In questo articolo spieghiamo perché abbiamo preso questa decisione e come abbiamo superato i problemi tecnici che abbiamo incontrato lungo la strada.
Valutazione delle nostre opzioni
Come SDK, il nostro codice viene eseguito all’interno delle applicazioni di altri sviluppatori e, a loro volta, dei loro processi applicativi. Per eseguire il collegamento web app in una WebView, Javascript deve essere abilitato. Questo apre la porta ad altre app per eseguire codice dannoso, come la registrazione di callback che cercano di intercettare nomi utente e password. Inoltre, un’app dannosa potrebbe aprire un’altra pagina Web che imita il flusso di link in un tentativo di phishing.
Alla ricerca di una soluzione facile da integrare per gli sviluppatori, intuitiva per gli utenti finali e sicura, abbiamo valutato diverse opzioni:
-
costruire un flusso di collegamento nativo: poiché i flussi di collegamento nativi venivano eseguiti anche nel processo di un’altra app, gli sviluppatori esperti potevano usare reflection per trovare i nostri EDITTEXT di input e registrare i callback in modo simile a Javascript in una WebView.
-
creazione di un’app di autenticazione separata: Ciò fornirebbe un’esperienza sandbox nativa e sarebbe un’esperienza ideale per gli utenti finali; tuttavia, molti utenti non vorrebbero scaricare un’app extra dal Play Store. Ciò significa che avremmo bisogno di una soluzione di fallback per gli utenti che si rifiutano di scaricare l’app.
-
apertura del collegamento in una finestra del browser separata: questa sarebbe una soluzione sandbox e sicura. Quasi tutti gli utenti hanno un browser installato, ma il passaggio contestuale da un’app a un browser introdurrebbe un ritardo notevole, specialmente sui dispositivi di fascia bassa.
-
utilizzo delle schede personalizzate di Chrome: Questa è la soluzione che abbiamo scelto, in quanto non aveva nessuno degli inconvenienti sopra menzionati.
La nostra scelta: Chrome Custom Tabs
Chrome custom tabs (CCT) è una parte del browser Chrome che si integra con il framework Android per consentire alle app di aprire siti Web in un processo leggero. CCT si apre più velocemente di un browser e, se precaricato tramite la sua chiamata di riscaldamento, è potenzialmente anche più veloce di una WebView. Mentre viene ancora eseguito Javascript, è nel suo processo, che impedisce alle app di eseguire codice dannoso. Inoltre, l’interfaccia utente CCT fornisce una barra delle azioni che mostra l’URL della pagina caricata, insieme a un’icona di blocco di verifica SSL per le pagine sicure. Questo rassicura gli utenti che viene mostrata la pagina corretta.
Anche se non tutti gli utenti hanno installato Chrome, la stragrande maggioranza lo fanno. Per coloro che non lo fanno, stiamo usando il metodo di fallback del browser descritto sopra (opzione 3); oltre ad aggiungere una riga di codice, otteniamo il fallback gratuitamente da CCT. Come notato prima, il fallback del browser non è l’esperienza utente ideale a causa della sua latenza, ma mantiene l’alto livello di sicurezza richiesto da Plaid.
Come si è sviluppata la CCT soluzione, abbiamo incontrato e affrontato diverse complicazioni:
-
Ottenere dati di evento
-
Recupero il risultato finale
-
Controlla il CCT attività di & processo
Ottenere Dati dell’Evento
Quando un utente naviga tra gli schermi di Collegamento, un reindirizzamento e di dati è fornito agli sviluppatori nei parametri URL.
Queste informazioni di reindirizzamento sono preziose per gli sviluppatori, in quanto li aiutano a capire il comportamento degli utenti. Con CCT in esecuzione nel proprio processo e non fornendo un callback di reindirizzamento, queste informazioni sarebbero normalmente inaccessibili, il che renderebbe il nostro SDK sicuro meno funzionale per gli sviluppatori rispetto alle loro implementazioni WebView personalizzate.
Per fornire queste informazioni da CCT, abbiamo invece registrato gli eventi di reindirizzamento sul server in un datastore Redis. Quando l’SDK apre Link, effettua una chiamata bootstrap ai nostri server, che forniscono un ID canale per utente scelto da noi e una chiave segreta. L’SDK crea quindi un oggetto worker con ambito app, che esegue il polling del server utilizzando un flusso di intervalli RX. Su ogni chiamata di polling forniamo al server l’ID del canale, la chiave segreta e l’UUID dell’ultimo evento (o null) per ottenere gli ultimi eventi.
Osservabili.intervallo (intervallo, TimeUnit.SECONDI).subscribeOn(Pianificatori.calcolo()).observeOn (AndroidSchedulers.mainThread()).flatMapSingle (makeNetworkCall()).iscriviti({// Gestire i messaggi},{// Gestire gli errori})
Il framework Android può uccidere qualsiasi processo, tra cui l’app utilizza Plaid SDK. Poiché l’oggetto worker è legato all’applicazione, ciò comporterebbe l’arresto del worker. Se l’utente ha continuato il flusso, (con successo o senza successo) l’SDK effettuerebbe una chiamata finale al canale e otterrebbe gli eventi rimanenti. Gli eventi andrebbero persi solo se l’utente interrompesse il flusso e la forza uccidesse l’app.
Recupero del risultato finale
Simile al passaggio dei dati degli eventi ai client, Link utilizza l’URL per segnalare che l’utente ha completato il flusso. L’URL pertinente include i dati necessari, come la chiave pubblica o un codice di errore.
Poiché non possiamo accedere all’URL con CCT, abbiamo memorizzato il risultato finale in Redis con lo stesso ID canale. Mentre questo significa che il nostro operatore di polling saprebbe quando Link ha finito, non ci sarebbe alcuna garanzia che il lavoratore sarebbe ancora vivo. Anche se fosse vivo, l’utente potrebbe dover attendere la prossima chiamata di polling per la consegna del risultato, che potrebbe essere un lungo paio di secondi.
Per garantire che un risultato venga consegnato in modo tempestivo, utilizziamo un deep link per riaprire l’SDK. Il collegamento profondo viene creato utilizzando l’ID app dell’applicazione, che deve essere associato al segreto client e inserito nella whitelist nella dashboard degli sviluppatori. Questo, oltre al fatto che solo un’app su un dispositivo può avere lo stesso ID app, non garantisce che altre app intercettino il reindirizzamento. L’app Web Link crea quindi un URI di intento, che viene attivato alla fine del flusso di collegamento.
intento://redirect/#Intento;schema=plaid;pacchetto=$nomepacchetto;end;
il Nostro SDK include un filtro di intento per gestire l’URI, in modo che l’applicazione riapre e fa una chiamata direttamente al canale immediatamente.
<intent-filter><action android:name="android.intento.azione.VISTA" /><categoria android: nome = " android.intento.categoria.PREDEFINITO" /><categoria android: nome = " android.intento.categoria.SFOGLIABILE" /><datiandroid: host= "redirect"Android:schema="plaid" /></intent-filter>
Controllo CCT
CCT manca di interfacce per app:
-
ascoltare per quando l’utente chiude l’attività
-
rilevare quando l’utente ha cliccato su “Apri nel Browser” opzione
-
la forza di chiudere
Abbiamo lavorato con successo in giro tutti questi difetti.
Innanzitutto, per ascoltare quando l’utente chiude l’attività, apriamo CCT usando startActivityForResult e gli passiamo un codice di richiesta. Se l’utente chiude CCT utilizzando la X nell’angolo in alto a sinistra del pulsante system back, il callback onActivityResult viene attivato con il codice di richiesta che abbiamo fornito e un codice di risultato dell’attività.RESULT_CANCELED. L’intento dei dati non include alcuna informazione, ma possiamo effettuare una chiamata finale al canale per ottenere gli eventi rimanenti. Quindi li passiamo all’app client e restituiamo un oggetto LinkCancellation, segnalando che il collegamento è stato chiuso intenzionalmente dall’utente.
Successivamente, la potenziale preoccupazione di rilevare quando l’utente ha fatto clic su “Apri nel browser” è che l’utente potrebbe quindi passare attraverso l’intero flusso in un’applicazione separata, ovvero il browser. Questo non è un problema per noi, perché i sistemi di polling e intenti continuano a funzionare allo stesso modo e possiamo ancora ottenere i dati necessari.
Infine, quando l’utente completa correttamente il flusso e l’intento del risultato viene attivato, il processo CCT rimarrà aperto e nell’elenco delle attività dell’utente. Questo processo fantasma non solo sarebbe uno spreco, ma potrebbe anche essere fonte di confusione per un utente quando preme il pulsante di sistema “attività recenti”. Pertanto, abbiamo bisogno di un modo per forzare CCT a chiudere quando il flusso è completo.
Per fare ciò, abbiamo usato il modello mostrato nella libreria OpenID AppAuth per Android. Invece di gestire il risultato nell’attività che apre il collegamento, posizioniamo il filtro intent su un’attività separata. Questa seconda attività gestisce tutti i reindirizzamenti dall’app Web, che includono: completamenti riusciti, errori che chiudono il flusso, reindirizzamenti OAuth o App-to-App e errori di sistema generali. L’attività passa quindi i dati all’attività di apertura utilizzando un intento con l’Intento.FLAG_ACTIVITY_SINGLE_TOP e Intento.FLAG_ACTIVITY_CLEAR_TOP bandiere. Usati insieme, cancellano tutto nello stack sopra l’attività di apertura, incluso il CCT.
val intent = Intent(attività, LinkActivity::class.java)quando (state) {viene RedirectState.ChromeCustomTabsComplete -> {intento.putExtra (LINK_CHROME_CUSTOM_TABS_COMPLETE_REDIRECT, true)intento.putExtra(LINK_RESULT_CODE, state.resultCode)intent.putExtra(LINK_RESULT, state.result)}is RedirectState.UserInitiatedChromeCustomTabsViewClose -> {intent.putExtra(LINK_CHROME_CUSTOM_TABS_USER_CLOSE_REDIRECT, true)}is RedirectState.OAuth -> {intent.putExtra(LINK_OAUTH_REDIRECT, true)intent.putExtra(LINK_OAUTH_STATE_ID, state.oauthStateId)}is RedirectState.RedirectError ->intent.putExtra (LINK_REDIRECT_ERROR, true)}intento.flags = Intento.FLAG_ACTIVITY_SINGLE_TOP o Intento.FLAG_ACTIVITY_CLEAR_TOPintento di ritorno
Considerazioni finali su CCT
Al fine di fornire un’esperienza sicura e sandbox non disponibile nelle visualizzazioni Web o nei flussi nativi, CCT è una soluzione praticabile. È facile da integrare per gli sviluppatori e offre un’esperienza utente migliore rispetto all’apertura delle finestre del browser grazie alla sua natura leggera e alla sua velocità.
La natura sandbox di CCT e l’API limitata significano che non è priva dei suoi aspetti negativi. Ascoltare i reindirizzamenti degli URL, ottenere i risultati finali e controllare il processo CCT ci ha richiesto di trovare soluzioni creative. Queste soluzioni si basavano su una comprensione delle funzionalità integrate di Android, in particolare del framework intent.
I vantaggi per sviluppatori e consumatori valevano lo sforzo richiesto e raccomandiamo di utilizzare CCT in altre app e SDK per un’integrazione rapida e sicura. Inoltre, puoi utilizzare i suggerimenti forniti qui per migliorare l’esperienza dell’utente (e dello sviluppatore).
Se sei interessato a risolvere problemi unici che verranno utilizzati da migliaia di sviluppatori e milioni di consumatori, visita la nostra pagina carriere.