Integrazioni native con Flutter

03.05.2023

Integrazioni native con Flutter ed a cosa servono

Creare integrazioni native con Flutter permette di sfruttare a pieno il potenziale dei dispositivi, introducendo funzionalità altrimenti assenti. Ciò può essere utile quando si intende sviluppare app avanzate, che comprendano funzionalità di monitoraggio in background, integrazioni con librerie native e altro ancora.

In questo articolo spiegherò come Flutter collabora con il nativo, cosa sono i platform channel e come possiamo sfruttarli.

Funzionalità native nei plugin di Flutter: quali sono?

Innanzitutto, Flutter offre molte funzionalità native attraverso i suoi plugin. Quest’ultimi permettono agli sviluppatori di accedere a librerie e funzionalità native senza ricorrere a integrazioni su misura.

Ecco una breve lista delle funzionalità che sono fornite dai plugin di flutter:

  • Fotocamera: consente agli sviluppatori di accedere alla fotocamera del dispositivo e di acquisire immagini e video; ciò è particolarmente utile per le app di fotografia o per la scansione di codici QR.

  • Posizione: permette agli sviluppatori di accedere ai dati di posizione del dispositivo, consentendo la creazione, ad esempio, di app di navigazione o di localizzazione.

  • Sensori: consente agli sviluppatori di accedere ai sensori del dispositivo, come il giroscopio e l'accelerometro, grazie ai quali possono essere create varie tipologie di app, come quelle dedicate al fitness e i giochi.

  • Notifiche push: la possibilità di inviare notifiche push consente agli sviluppatori di costruire app che inviano notifiche agli utenti su nuovi contenuti o eventi.

  • Connessione Bluetooth: grazie a questo plugin è possibile realizzare app che si occupano di monitorare o comandare dispositivi esterni via Bluetooth.

Queste funzionalità si possono implementare in Flutter semplicemente installando i plugin già disponibili. La situazione però si complica quando i plugin disponibili non sono sufficienti per raggiungere l'obiettivo desiderato.

Quando i plugin non bastano: i platform channel

Quali sono le difficoltà che si possono riscontrare a cui i plugin non possono far fronte? Alcuni esempi sono:

  1. L’integrazione con SDK esterni che non supportano Flutter,

  2. Il monitoraggio di dispositivi Bluetooth in background,

  3. La gestione avanzata delle notifiche push, ad esempio eseguire codice all’arrivo di una notifica,

  4. Estensioni del funzionamento dell’app attraverso funzionalità di sistema, come i widget.

Flutter risolve questo problema mettendo a disposizione i platform channel.

Per comprenderne il funzionamento, è importante sottolineare che Flutter è sempre ospitato all'interno di un'applicazione nativa specifica per la piattaforma in cui viene utilizzato. Concretamente, questo significa che su iOS Flutter viene ospitato all'interno di un'app scritta in Swift, che istanzia un componente nativo, ovvero un ViewController, il quale contiene e mostra all’utente l’applicazione Flutter.

I platform channel sono un meccanismo di comunicazione asincrona utile per inviare e ricevere messaggi dall’app Flutter all’app contenitore e viceversa. Vediamo in seguito alcuni di questi e le loro caratteristiche.

Message channel

I message channel sono platform channel progettati per inviare informazioni di vario tipo da Flutter a nativo e viceversa.

Al livello più basso, Flutter dialoga con l’app che lo contiene attraverso i binary message channel. Solitamente non si utilizza questo tipo di comunicazione, in quanto il trasferimento di informazioni attraverso questo canale deve avvenire in maniera binaria. Ciò significa che dovremo scrivere i valori che intendiamo comunicare all’interno di un buffer di memoria e poi, alla ricezione del messaggio, andare a leggerli interpretandone il contenuto attraverso le API specifiche che ciascuna piattaforma mette a disposizione.

Ecco un esempio di utilizzo del binary channel:

Questo metodo invia un messaggio che contiene un Float64 e un Int32 e si aspetta una risposta di tipo stringa in formato UTF-8

Segue la controparte Swift, che si mette in ascolto del messaggio, ne interpreta il contenuto e invia una risposta:

Codifica e decodifica dei dati

Come si nota dall’esempio, per comunicare in questo modo è necessario scrivere parecchio codice. Inoltre, il rischio di introdurre bug è molto elevato.

Per questi motivi Flutter mette a disposizione anche alcuni codec per facilitare l’interpretazione dei dati che passiamo. I codec sono software che consentono di codificare e decodificare i dati digitali. Alcuni esempi sono i formati .mp3 e .jpeg o, per quanto riguarda il channel, impostando uno StringCodec() sapremo quindi che il contenuto del messaggio sarà una stringa.

I codec forniti da Flutter sono quattro:

  • BinaryCodec: rappresenta il modo di inviare dati più di basso livello.

  • StringCodec: permette di inviare messaggi di testo in formato UTF-8.

  • JSONMessageCodec: serve per l’invio di oggetti, anche annidati, in formato JSON.

  • StandardMessageCodec: utile per inviare liste omogenee e altri tipi di oggetti.

È però anche possibile creare dei codec su misura in base alle esigenze.

Method channel

I method channel sono platform channel progettati per invocare dei "pezzi di codice con un nome”. Sono utili quando intendiamo mettere a disposizione di Flutter un metodo nativo o viceversa. Tuttavia, non sono strettamente legati ad un metodo; siamo noi a dover leggere il nome all’interno del messaggio e invocare il metodo corrispondente, quindi potrebbe anche essere impiegato per eseguire un pezzo di codice.

Il method channel funziona in maniera molto simile al message channel, infatti è equivalente ad usare un binaryMessageChannel specificando un codec speciale, detto method codec, che viene creato su misura sulla base dei parametri del metodo. Oltre ai parametri, nel method codec vengono specificate anche altre informazioni che riguardano la gestione della risposta nel caso di successo o fallimento e l’eventuale errore.

Vediamo ora un esempio in cui Flutter chiama un metodo nativo attraverso un method channel:

Esempio di richiesta al method channel con Dart

Controparte Swift, che riceve la richiesta, invoca il metodo corrispondente e fornisce la risposta

Per approfondire ulteriormente i vari tipi di channel e codec consiglio questo articolo su Medium che tratta più nel dettaglio i platform channel.

Cos’è Pigeon e come può aiutarci

Pigeon è uno strumento che genera automaticamente i platform channel di cui abbiamo bisogno. Per comunicare a Pigeon quali metodi nativi vogliamo che siano accessibili lato Flutter dobbiamo creare una classe astratta che contenga le firme dei metodi e lui si occuperà di generare il resto.

Grazie a Pigeon è possibile mettere in comunicazione Dart e il codice nativo in modo facile e veloce, senza dover creare manualmente i platform channel e riducendo quindi anche la probabilità di introdurre bug.

Esempio di implementazione

Innanzitutto, è bene specificare che l’intenzione di questo esempio è solo quella di dare un’idea sul funzionamento e le potenzialità di Pigeon. Se intendi usarlo nella tua app, fai riferimento alla documentazione ufficiale.

Supponiamo di voler implementare nella nostra app flutter un SDK esterno non compatibile con Flutter. Questo SDK permette alla nostra app di comunicare via Bluetooth con una porta in maniera sicura. Il risultato che vogliamo ottenere è di poter controllare la porta e visualizzarne lo stato tramite la UI che abbiamo creato in Flutter.

In questo caso Pigeon fa al caso nostro! Aggiungiamolo al nostro progetto con il comando: dart pub add pigeon.

Una volta installato, possiamo procedere a creare la classe astratta che contiene i metodi di cui abbiamo bisogno, ad esempio:

Per avviare la generazione automatica va creato uno script. Il seguente esempio genera codice per Android e iOS, ma è possibile farlo anche per le altre piattaforme seguendo la documentazione.

Se intendi usare Pigeon per mettere in comunicazione Flutter con Android e iOS puoi copiare questo script ma ricorda di sostituire i percorsi e i nomi dei file che saranno diversi nel tuo caso.

Una volta generato il codice, è possibile scrivere l’implementazione dei metodi lato nativo. Per fare ciò, va creata una classe che implementi l’interfaccia generata dallo script.

Ad esempio, in Swift dobbiamo creare una nuova classe che implementa l’interfaccia DomoticsApi che abbiamo definito precedentemente.

Una volta creata questa classe dobbiamo implementare i metodi che abbiamo definito prima. Se usiamo Xcode, ci proporrà direttamente lui di implementarli con un messaggio come il seguente:

Il risultato sarà qualcosa di questo tipo:

L’ultimo step è il collegamento del channel a Flutter. A questo scopo è sufficiente implementare questa funzione e chiamarla all’interno del metodo didFinishLaunching dell’AppDelegate.

Una volta terminata l’implementazione nativa, possiamo accedere ai metodi nativi direttamente da Flutter.

Esempio di chiamata al metodo nativo openDoor e gestione degli errori

Flutter non ha più limiti

Grazie all'utilizzo di Pigeon è possibile integrare rapidamente il codice nativo in Flutter e ciò permette anche di sfruttare al meglio le potenzialità delle piattaforme native. In questo modo le potenzialità di Flutter sono incrementate al punto che siamo in grado di realizzare praticamente qualsiasi tipo di applicazione, offrendo una user experience eccellente e, al contempo, mantenendo una base di codice unificata.

Hai un’idea o vuoi conoscerci meglio?

In alternativa possiamo giocare a calcio balilla o fare una partita di ping pong in ufficio. Abbiamo anche una macchina per fare le granite. Insomma, contattaci per qualsiasi cosa, no televendite però.

Iscriviti alla newsletter

Niente Spam! Di tanto in tanto condivideremo con te articoli del nostro blog, playlist, foto e aneddoti sulla vita in ufficio.

Inserendo il tuo indirizzo confermi di aver letto la privacy policy e ci dai il permesso di aggiornarti via email per le finalità di marketing descritte nell’informativa.

Where we are

Via Cadorna 2,
Albignasego Padova,
35020 Italia

Copyright 2024 - Mabiloft SRL - P.IVA 05157070284 - C.SOCIALE €10.000 I.V.