BlogRight arrowTutorialRight ArrowTutorial: come implementare gli acquisti in-app in un'app Flutter
BlogRight arrowTutorialRight ArrowTutorial: come implementare gli acquisti in-app in un'app Flutter

Tutorial: come implementare gli acquisti in-app in un'app Flutter

Tutorial: come implementare gli acquisti in-app in un'app Flutter
Listen to the episode
Tutorial: come implementare gli acquisti in-app in un'app Flutter

Flutter è un framework relativamente nuovo sviluppato da Google che consente di creare rapidamente applicazioni multipiattaforma. L’altro framework popolare è React Native di Facebook. Le app Flutter sono costruite contemporaneamente per iOS e per Android. Di conseguenza, una libreria di acquisti deve essere compatibile sia con StoreKit che con la Libreria Fatturazione (Billing Library). 

Dal punto di vista dell'architettura, qualsiasi plugin di pagamento, compreso il nostro SDK Adapty Flutter, è un wrapper attorno alle librerie native, StoreKit e Libreria Fatturazione. Nel nostro caso, si tratta di un wrapper intorno alle nostre librerie  iOS Adapty e  SDK Android

Librerie open source per acquisti in-app (in-app purchases) nelle app basate su Flutter

Le soluzioni più diffuse per gli acquisti nelle applicazioni Flutter sono i plugin open source in_app_purchase (sviluppato dal team che si occupa di Flutter) e flutter_inapp_purchase (plugin non ufficiale). 

Questi plugin sono stati realizzati per implementare gli acquisti lato client. Non dispongono della convalida delle ricevute (receipt validation) lato server (server-side). Dovrai configurare la tua infrastruttura lato server per convalidare le ricevute e raccogliere le analisi dei pagamenti relativi a rinnovi (renewals), rimborsi (refunds), test, annullamenti e altro ancora. 

Inoltre, queste librerie sono solitamente lente nel supportare le nuove funzionalità del negozio. Solo per citarne alcune, al momento mancano le offerte promozionali (promo offers), le funzioni pagamento in mobilità (pay-as-you-go) e la funzione pagamento anticipato (pay upfront) per iOS.

Poiché la nostra libreria parla con il nostro server, è dotata di tutte queste caratteristiche:

  • Convalida d’acquisto del server (purchase validation); 
  • Supporto completo delle funzioni native di pagamento; 
  • Sintassi DRY;
  • Analisi degli abbonamenti e degli acquisti e raccolta di altri dati;
  • Test A/B (A/B tests), oltre alle sperimentazioni rapide di acquisti, prezzi e periodi promozionali;
  • Paywall e offerte promozionali.

Per tenere questo articolo breve e di facile lettura, ti lasciamo il link ad alcuni articoli che abbiamo scritto in precedenza su alcuni passi che sarebbe consigliabile tu intraprendessi prima di iniziare a lavorare sugli acquisti per la tua applicazione Flutter.

⭐️ Download our guide on in-app techniques which will make in-app purchases in your app perfect

Creazione degli acquisti su iOS e Android

Innanzitutto, se non hai un account sviluppatore, dovrai crearne uno. In seguito, dovrai creare un acquisto settimanale sia per iOS che per Android. Spieghiamo come farlo in alcuni articoli precedenti, di cui lasciamo il link di seguito:

Creazione di acquisti per iOS

Creazione di acquisti per Android

Una volta terminato, potrai iniziare a creare e configurare il progetto.

Creazione e configurazione del progetto

Per far funzionare i tuoi acquisti sia nella tua implementazione (implementation) che nel nostro sistema, dovrai inserire questi dettagli tecnici.

Per iOS, è necessario:

  • Specificare l'ID del bundle per collegare il progetto Adapty alla tua app;
  • Impostare le notifiche del server (server notifications) App Store in App Store Connect, in modo da poter essere avvisati degli eventi (events) di abbonamento;
  • Specificare il segreto condiviso (shared secret) dell'App Store, che il server Adapty utilizzerà per stabilire una connessione con i server Apple e convalidare le ricevute.

Per Android, è necessario specificare sia il nome del pacchetto che il file chiave dell'account di servizio. Il nome del pacchetto è l'ID del bundle iOS per Android. È necessario utilizzare lo stesso utilizzato nel codice. Si trova nel file /android/app/build.gradle, nella directory android.defaultConfig.applicationId .

Configurazione di prodotti (products) e paywall 

Un prodotto Adapty comprende quelli di diversi negozi. Per ora ci sono solo App Store e Google Play, ma in futuro ne introdurremo altri. L'idea alla base di questo approccio è di rendere più semplice la raccolta di statistiche su più piattaforme e di consentire di lavorare con entità di primo livello, invece che con identificativi.

Paywall è un'entità astratta che contiene un array di prodotti e un file di configurazione remota (che è un file JSON contenente i metadati specificati nella dashboard). Tu specifichi l'ID del paywall nel codice della tua app, che verrà utilizzato per recuperare il file di configurazione e i dati del prodotto. È possibile modificare entrambi senza dover aggiornare l'app. Nello scenario abituale, tu progetti il paywall e lo popoli con i dati ricevuti da noi.

Creazione di un prodotto

Ora, usiamo la Console Google Play e App Store Connect per creare un prodotto corrispondente a un abbonamento settimanale. Inserisci l'ID dei prodotti corrispondenti, che potrai recuperare dai sistemi di pagamento. È importante notare che, poiché App Store Connect non dispone di API (API), è necessario eseguire questa operazione manualmente. Tuttavia, basterà farlo una volta sola.

Creazione di un paywall

Quando si crea un paywall, la cosa fondamentale è specificare il suo ID in un formato conveniente. Questo identificativo verrà successivamente utilizzato dall'SDK per richiedere i dati del paywall. Noi riteniamo che il seguente sia un buon approccio: Con questa architettura, non c'è bisogno di codificare i prodotti lato client. Si può essere flessibili con la gestione dei prodotti, il versioning, i test, ecc. L’alternativa sarebbe Firebase JSON con una serie di prodotti integrati. Tuttavia, questo non fornisce la convalida degli errori e non è altrettanto intuitivo.

Ecco fatto! Dopo aver creato un prodotto e un paywall, sei pronto per il primo acquisto. Procediamo all’installazione dell’SDK.

Come usare l’SDK

Vediamo le funzioni principali di cui avremo bisogno per configurare e utilizzare gli abbonamenti.

Installazione della libreria

Per prima cosa, è necessario aggiungere la libreria adapty_flutter al progetto. Per farlo, aggiungi la seguente dipendenza al file pubspec.yaml:

dependencies:
  adapty_flutter: ^1.0.4

Quindi, esegui:

flutter pub get

Da qui, potrai importare l'SDK di Adapty nella tua app in questo modo:

import 'package:adapty_flutter/adapty_flutter.dart';
Start for free

Convenient in-app purchases infrastructure.

Adapty SDK has it all:
— server-side purchase validation,
— all side cases covered,
— simple implementation.

Start for free

Configurazione

Dovrai configurare la tua app affinché funzioni con Adapty. Per farlo, aggiungi il flag AdaptyPublicSdkKey con la tua chiave SDK in Info.plist (per iOS) o in AndroidManifest.xml (per Android).

Puoi trovare la tua chiave SDK negli Adapty settings:

Info.plist:

<dict>
	...     
		<key>AdaptyPublicSdkKey</key>
    

AndroidManifest.xml:

<application ...>
        ...
        <meta-data
               android:name="AdaptyPublicSdkKey"
               android:value="PUBLIC_SDK_KEY" />
 </application>

Quindi, attiva l'SDK richiamando questo codice sul lato Flutter, ad esempio nel metodo main() del progetto:

void main() {
   runZoned(() async {
     Adapty.activate();
     final installId = await Service.getOrCreateInstallId();
     await Adapty.identify(***customer-user-id***);
     await Adapty.setLogLevel(AdaptyLogLevel.verbose);
     runApp(MyApp());
  });
 }

La funzione void Adapty.activate() attiva la libreriaAdapty_Flutter:

Future<bool> Adapty.identify(String customerUserId)

Adapty.identify consente di recuperare l'id dell'utente. Adapty lo invia ai sistemi di abbonamento e di analisi per assegnare gli eventi a questo profilo. Potrai anche trovare i tuoi clienti con customerUserId in Profiles.

Adapty registra i messaggi di errore e altri dati importanti per aiutarti a capire cosa stia succedendo.

Future<void> Adapty.identify(AdaptyLogLevel value)

La funzione consente di scegliere uno dei tre valori possibili:

  • AdaptyLogLevel.none (impostazione predefinita): non verrà registrato nulla.
  • AdaptyLogLevel.errors: verranno registrati solo i messaggi di errore. 
  • AdaptyLogLevel.verbose: le chiamate del metodo, le richieste e le risposte dell'API e i messaggi di errore saranno registrati. 

Recupero dei paywall

Per recuperare l'elenco dei paywall, esegui questo codice:

try {
  final GetPaywallsResult getPaywallsResult = await Adapty.getPaywalls(forceUpdate: Bool);
  final List<AdaptyPaywall> paywalls = getPaywallsResult.paywalls;
 } on AdaptyError(adaptyError) {}
  catch(e) {}

La funzione Adapty.getPaywalls() restituisce l'oggetto GetPaywallsResult che contiene:

  • Paywall: un array di paywall ( AdaptyPaywall ). Il modello contiene l'elenco dei prodotti, l'ID del paywall, il payload personalizzato e alcuni altri valori.

Effettuazione degli acquisti 

Nel passaggio precedente, è stato recuperato l'array del paywall. Ora cercheremo quello che serve per visualizzare i prodotti nell'interfaccia utente. Supponiamo che questo paywall si chiami your_paywall_id:

final List? paywalls = getPaywallsResult.paywalls;
    myPaywall = paywalls?.firstWhere((paywall) => paywall.developerId == "your_paywall_id", orElse: null);

Quindi, utilizzando l'array di prodotti del campo prodotti, visualizza tutti gli elementi. Supponiamo che l'utente voglia acquistare il primo prodotto. Per semplicità, assumeremo che sia il primo elemento dell'array di prodotti. 

final AdaptyProduct? product = myPaywall?.products?.first;

Per avviare l'acquisto, richiama la funzione makePurchaseResult. (Ricordati di racchiudere il tutto in un blocco try-catch per ricevere comunque tutti i messaggi di errore dall'SDK).

final MakePurchaseResult makePurchaseResult = await Adapty.makePurchase(product);

Una volta eseguita la funzione, la variabile makePurchaseResult assumerà il risultato come valore. Ecco come verificare il livello di accesso dopo aver completato l'acquisto: 

final isPremium = makePurchaseResult?.purchaserInfo?.accessLevels['premium']?.isActive ?? false;

Nota che AdaptyErrorCode.paymentCancelled significa che l'utente ha annullato l'acquisto da solo, il che significa che non si tratta di un vero e proprio messaggio di errore. 

Per ripristinare gli acquisti, utilizza il metodo .restorePurchases():

try {
	final RestorePurchasesResult restorePurchasesResult = await Adapty.restorePurchases();
// "premium" is an identifier of default access level
  if (restorePurchasesResult?.purchaserInfo?.accessLevels['premium']?.isActive ?? false) {
  	// grant access to premium features
  }
} on AdaptyError catch (adaptyError) {}
catch (e) {}

Tieni conto che sia l’oggetto MakePurchaseResult che il RestorePurchasesResult includono purchaserInfo. Questo oggetto contiene dati sui livelli di accesso, sugli abbonamenti e sugli acquisti. Di solito, per sapere se l'utente può accedere alle funzioni premium della tua  app basta controllare il suo livello di accesso.

Stato abbonamento

Per evitare di dover controllare l'intera catena di transazioni precedenti, introduciamo il termine "livello di accesso". Il livello di accesso è un flag che spiega a quante funzionalità dell'applicazione può accedere l'utente. Se non ha ancora effettuato acquisti, il suo livello di accesso sarà nullo. Altrimenti, sarà quello che avrai specificato per il tuo prodotto.

Ad esempio, si possono avere due livelli di accesso, argento e oro. Acquisti diversi sbloccano livelli di accesso e funzionalità diverse. La maggior parte delle app ha un solo livello di accesso.

Per vedere se l'abbonamento è attivo, è sufficiente verificare se l'utente abbia un livello di accesso attivo. Puoi usare il metodo the.getPurchaserInfo() e fare semplicemente questo:

try {
	AdaptyPurchaserInfo purchaserInfo = await Adapty.getPurchaserInfo();
   // "premium" is an identifier of default access level
  if (purchaserInfo.accessLevels['premium']?.isActive ?? false) {
  	// grant access to premium features
  }
} on AdaptyError catch (adaptyError) {}
catch (e) {}

Inoltre, puoi sottoscrivere il flusso .purchaserInfoUpdateStream per sapere tempestivamente quali eventuali modifiche abbia subito il livello di accesso dell’abbonato. Ecco come: 

Adapty.purchaserInfoUpdateStream.listen((purchaserInfo) {
  print('#Adapty# Purchaser Info Updated');
	if (purchaserInfo.accessLevels['premium'].isActive) {
  	// grant access to premium features
  }
});

Conclusione

Abbiamo progettato il nostro SDK in modo da aiutarti a integrare rapidamente i pagamenti nella tua app.  In più, abbiamo cercato di semplificare tutti gli altri passaggi che potresti dover compiere, come i test AB (A/B test), le analisi e le ulteriori integrazioni (integrations).

Se il tuo fatturato è inferiore a 10.000 $ al mese, ti forniremo gratuitamente tutte le funzionalità di acquisto. Risparmiati mesi di lavoro e concentrati sulla cosa più importante: il tuo prodotto.

Further reading

Is the App Store revenue cut too high?
Is the App Store revenue cut too high?
June 25, 2020
5 min read
IDFA changes are here. What do we know, and are we ready?
IDFA changes are here. What do we know, and are we ready?
April 28, 2021
16 min read
Webflow + selfserved Ghost blog with Caddy
Webflow + selfserved Ghost blog with Caddy
June 6, 2020
3 min read