# Pubblicare un'app: Google Play e App Store

Il percorso fatto con Quanto Basta e Faraway Score (settembre 2026), scritto
per rifarlo con le app successive. I dettagli di ciascuna stanno nel suo
repository (per Quanto Basta `docs/BUILD.md` e `docs/store/`): qui c'è quello
che vale per tutte.

## Prima di tutto, sul sito

Gli store vogliono due indirizzi, e li mettiamo su duebytes.it (istruzioni in
`_private/duebytes/CLAUDE.md`, sezione «Pagine delle app»):

- **assistenza**: `https://www.duebytes.it/<app>/`, in italiano e inglese;
- **informativa privacy**: `https://www.duebytes.it/<app>/privacy/`.

Poi l'app va aggiunta alla **pagina dei tester** `https://www.duebytes.it/beta/`
seguendo `_private/duebytes/beta/LEGGIMI.md`. È l'unico indirizzo che Paolo dà
ai tester: non si invita nessuno uno a uno.
Dal 25/09/2026 la pagina ha una scheda per app con due tasti (iOS, Android)
che aprono le istruzioni in una finestra; l'ordine delle app lo decide Paolo.
Tre sessioni la toccano: si riparte sempre dalla versione online e, dopo
averla caricata, si avvisano le altre (vedi il LEGGIMI).

## Firmare le build

**Android.** Google tiene la chiave di firma vera (Play App Signing); noi
firmiamo con una **chiave di caricamento**, una per app, creata con `keytool`
e tenuta fuori dal repository, accanto al progetto:
`_private/ - App/<App> - firma Android/` con `upload.keystore` e
`credenziali.txt`. La build la trova con le proprietà
`<PREFISSO>_UPLOAD_STORE_FILE`, `_STORE_PASSWORD`, `_KEY_ALIAS`,
`_KEY_PASSWORD` in `~/.gradle/gradle.properties` (`QB_` per Quanto Basta,
`FW_` per Faraway). Con Expo le mette nel `build.gradle` un plugin
(`plugins/with-android-upload-key.js` di Quanto Basta), perché `android/` si
rigenera a ogni prebuild. Controllo prima di caricare:
`keytool -printcert -jarfile app-release.aab` deve dare l'impronta della
chiave di caricamento, non quella di debug.

**iOS.** Firma automatica col team `686XK96PF6` («Paolo Alberti»). Archivio e
caricamento su App Store Connect da terminale, senza aprire Xcode:

```bash
xcodebuild -workspace <App>.xcworkspace -scheme <App> -configuration Release \
  -destination 'generic/platform=iOS' -archivePath build/<App>.xcarchive archive \
  -allowProvisioningUpdates DEVELOPMENT_TEAM=686XK96PF6 CODE_SIGN_STYLE=Automatic
xcodebuild -exportArchive -archivePath build/<App>.xcarchive \
  -exportOptionsPlist "/Users/paolo/Server/Siti Web/_private/ - App/comune/ios/ExportOptions.plist" \
  -exportPath build/export -allowProvisioningUpdates
```

Ogni caricamento vuole un numero di build nuovo (iOS `CFBundleVersion`,
Android `versionCode`). Gli avvisi sui dSYM dei framework precompilati non
bloccano niente.

## Google Play

Account **personale** «Paolo Alberti - Duebytes», ID `8440704338946855239`,
proprietario `paoloalby@gmail.com`, email pubblica
`paolo.alberti@duebytes.it`, sito `https://www.duebytes.it`. Verifiche di
identità, dispositivo e telefono già passate.

1. **Crea app**: italiano come lingua predefinita, gratuita o a pagamento. Una
   app gratuita **non potrà più diventare a pagamento** (gli acquisti in-app
   restano possibili): per un'app a pagamento va scelto subito.
2. **Contenuti app**: norme sulla privacy (l'URL sopra), annunci, accesso,
   ID pubblicità, pubblico di destinazione, sicurezza dei dati,
   classificazione IARC. Le risposte date per Quanto Basta sono in
   `QuantoBasta/docs/store/google-play.md`: tenerle uguali a quelle di App
   Store Connect («App Privacy»).
3. **Scheda dello Store**: nome (uguale a quello dell'App Store), descrizione
   breve e completa, icona 512×512, immagine in evidenza 1024×500 senza
   trasparenza, screenshot del telefono. Gli screenshot dei tablet 7" e 10"
   (sezioni a parte) si possono lasciare vuoti: Faraway è andata in revisione
   senza. Se si mettono, devono mostrare l'app che gira sul tablet, non le
   slide del telefono (Quanto Basta li ha, perché sul tablet ha i due
   pannelli; vedi `comune/carosello/`). Alla fine chiede se ci sono immagini
   fatte con l'IA.
4. **Test chiuso**. Con l'account personale, prima della produzione Google
   vuole **almeno 12 tester iscritti per 14 giorni di fila** nel test chiuso
   (il test interno non conta). I tester sono un **gruppo Google**
   `tester-<app>@googlegroups.com`: chiunque può entrare, pubblicano solo i
   gestori. Il test chiuso in tutti i paesi, con il gruppo come tester.
5. **Release**: l'AAB supera i 10 MB, quindi **lo trascina Paolo** nella
   pagina (Claude lo prepara sulla Scrivania). Note di rilascio fra
   `<it-IT>` e `</it-IT>`. Poi Panoramica della pubblicazione → Invia per la
   revisione. L'avviso sul file di deoffuscamento non blocca.
   **Regola di Paolo (30/09/2026): i rilasci sono automatici.** La
   «Pubblicazione gestita» resta **disattivata**: appena Google approva, la
   release va online da sola, senza che nessuno debba controllare.

Trappole di Play Console:
- a volte dà «errore imprevisto» e rimbalza all'elenco delle app (che resta
  vuoto): si riapre la dashboard dell'app e si passa dal menu a sinistra;
- nella scheda gli screenshot si scelgono da una libreria: aggiungerli **uno
  alla volta** (freccia → Aggiungi) li mette in ordine; tutti insieme escono in
  ordine casuale e poi vanno trascinati. Dare nomi distinti ai file (es.
  `tablet-1.png`), perché la libreria è condivisa fra le sezioni.

## App Store Connect

Team individuale «Paolo Alberti» `686XK96PF6`. A livello di account è già
fatto tutto (settembre 2026): operatore commerciale per il DSA (indirizzo di
casa e cellulare, verificati con la visura camerale), DAC7 attiva, conto
Revolut. Il contratto «Paid Apps» in Accordi (non ancora firmato a settembre
2026) serve per un'app a pagamento **e** per gli acquisti in-app: Faraway resta
gratuita e senza acquisti (è la condizione dell'autorizzazione di Catch Up
Games), Quanto Basta ne prevede uno in futuro.

1. **Bundle ID** nel portale developer (`it.duebytes.<app>`), poi la nuova
   app. Il nome deve essere unico in tutto lo store, anche fra le app mai
   pubblicate: se è preso, si aggiunge un sottotitolo al nome («Quanto Basta:
   Dosaricette»); sotto l'icona resta il nome corto.
2. **Privacy dell'app**, **informazioni sull'app** (categoria, età),
   **prezzo e disponibilità**.
3. **TestFlight**: informazioni per i test (email per i riscontri, contatti
   per il revisore con un numero di telefono, che mette Paolo), gruppo interno
   «Interni» con Paolo, gruppo esterno «Beta tester» con il **link pubblico**
   (va sulla pagina dei tester). La prima build del gruppo esterno passa la
   verifica beta di Apple (in giornata); le build successive della stessa
   versione di solito sono approvate subito. Una build nuova entra da sola nel
   gruppo interno; in quello esterno si aggiunge a mano, con le note «cosa
   provare». **Regola di Paolo (26/09/2026): ogni build del gruppo interno va
   subito anche nel gruppo esterno**, senza aspettare che lui la chieda.
4. **Versione per lo store**: schermate 6,9" (le slide `ios`), testi, parole
   chiave, URL di assistenza, copyright «2026 Paolo Alberti», build, e in
   «Rilascio della versione» **«Rilascia automaticamente questa versione»**.
   Poi «Aggiungi alla verifica». **Regola di Paolo (30/09/2026): i rilasci
   sono automatici**, lui non vuole stare dietro alle approvazioni. La scelta
   vale per una versione sola: va rimessa a ogni nuova versione. Anche le
   beta non chiedono niente: una build approvata dalla verifica beta arriva
   da sola ai tester del gruppo esterno.
5. **Novità di questa versione** (regola di Paolo, 01/10/2026): elenco
   puntato, tecnico, conciso. Le funzioni nuove si elencano, una riga
   ciascuna; la grafica e le piccole correzioni stanno in una voce sola
   («Migliorie grafiche», «Correzioni e piccole migliorie»), mai nel
   dettaglio. Vale anche per Google Play. **Dopo l'uscita non si cambiano
   più**: restano per sempre nella «Cronologia versioni» dello store.
   Ribadito da Paolo il 01/10/2026: sintetiche, niente frasi lunghe. Per le
   piccole cose bastano voci come «Risolti problemi tecnici», «Sistemati
   bug», «Piccole migliorie grafiche»; con più voci, elenco col trattino
   `-`. Una versione tutta nuova si annuncia con una frase breve.

## Trappole viste con Quanto Basta (30/09/2026)

- **Una versione con una lingua nuova (per esempio l'inglese) si blocca
  all'invio** se in «Privacy dell'app» quella lingua non ha l'URL
  dell'informativa: si sceglie la lingua in alto a destra della pagina e si
  mette lo stesso indirizzo.
- **Condividi su iPhone (estensione con App Group)**: l'archivio fallisce con
  «Provisioning profile … doesn't match the entitlements … application-groups»
  finché l'App Group non esiste sul portale e non è attivato sui due App ID
  (app e `.share-extension`). Xcode da riga di comando non lo crea da solo.
- **Il caricamento dell'IPA a volte cade** («The network connection was
  lost», «The request timed out»): si rilancia `-exportArchive` sullo stesso
  archivio, di solito al secondo o terzo tentativo passa.
- **Rilascio automatico**: in Play Console «Pubblicazione gestita» spenta
  (approvata = pubblicata); in App Store Connect «Rilascia automaticamente
  questa versione». Così Paolo non deve seguire le approvazioni.

## Trappole viste con Faraway Score (24/09/2026)

App Store Connect:
- **Lingue nella scheda (visto con Spot The Spy, 01/10/2026).** Il riquadro
  «Lingua» dell'App Store non legge la scheda ma il pacchetto dell'app: le
  cartelle `.lproj` e `CFBundleLocalizations`. Un'app Expo che traduce in
  JavaScript risulta solo «EN». Rimedio in `app.json`: plugin
  `["expo-localization", {"supportedLocales": ["it","en","fr"]}]` più
  `"locales": {"it": "./locales/it.json", ...}` (file con
  `{"ios": {"CFBundleDisplayName": "..."}}`: le chiavi vanno **dentro
  `ios`**, altrimenti finiscono anche nelle stringhe Android e il lint della
  release fallisce con «ExtraTranslation»), poi prebuild. Su Android lo stesso plugin aggiunge
  la scelta della lingua per app. Da controllare anche nelle altre app Expo.
- **iPad.** Un'app dichiarata anche per iPad (`TARGETED_DEVICE_FAMILY = "1,2"`)
  non si invia senza le schermate iPad da 13". Se il design per tablet non
  c'è, si dichiara solo iPhone (`TARGETED_DEVICE_FAMILY = 1`): su iPad si
  installa lo stesso, in modalità iPhone. Un'app iPad solo in verticale vuole
  `UIRequiresFullScreen = true`, altrimenti il caricamento viene rifiutato.
- **Campi che spariscono.** La pagina della versione riempie i campi qualche
  secondo dopo il caricamento. Descrizione, parole chiave e URL salvati il
  giorno prima una volta risultavano vuoti davvero: dopo ogni salvataggio si
  ricarica la pagina e si ricontrolla.
- **Screenshot non elaborati.** Una slide può restare un riquadro grigio con
  la nuvola: in Gestione risorse multimediali si toglie e si ricarica, insieme
  a quelle dopo, una alla volta, per tenere l'ordine.
- **Menu a tendina** di paese e prezzo: il clic sulla voce filtrata a volte
  sceglie la prima della lista. Controllare sempre cosa è rimasto scelto.
- **Cina continentale**: toglierla dalla disponibilità (serve la
  registrazione ICP, che non abbiamo).
- `xcodebuild -exportArchive` che dà «No Accounts with App Store Connect
  Access»: la sessione dell'Apple ID in Xcode (Settings → Accounts) va
  rinnovata da Paolo, poi si rilancia solo l'export.
- **Build e numero di versione** (25/09/2026). Una build resta legata alla
  versione con cui è stata caricata (`MARKETING_VERSION`). Le build «1.0»
  caricate dopo l'invio della 1.0 non si possono collegare alla 1.0.1: prima
  di compilare un aggiornamento si alza `MARKETING_VERSION` (con Expo:
  `version` in app.json), non solo il numero di build.
- **UE non vendibile** (Faraway, 26/09/2026): 1.0 rilasciata, ma nei 27
  paesi UE «Non vendibile · Stato di operatore commerciale non fornito»
  (Prezzi e disponibilità → Gestisci), anche con la dichiarazione DSA fatta
  nell'app. Dopo il rilascio controllare sempre quella pagina, non solo lo
  stato «Pronta per la distribuzione». Il 28/09 capita a tutte e tre le app:
  Apple sta ancora verificando i documenti dati da Paolo il 23/09. Non si fa
  niente lato app, si aspetta. Controllo senza browser:
  `curl "https://itunes.apple.com/lookup?id=<id app>&country=it"` (0 risultati
  = non ancora in Italia; con `country=us` si vede la versione in vendita).
- **Allegati per il revisore**: non passano da una versione alla successiva.
  Se le note dicono «allegato il PDF», o lo si ricarica o si cambia la frase
  (Faraway: «allegato alla 1.0, rimandabile su richiesta»).

Google Play:
- **Tablet e verticale.** Con `targetSdk 36` Android 16 ignora
  `screenOrientation` su tablet e pieghevoli aperti. Per restare in verticale:
  `<property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY" android:value="true" />`
  nell'`<application>` (così in Quanto Basta, col plugin
  `plugins/with-android-solo-verticale.js`, provato sull'emulatore tablet) o
  nell'activity. Vale solo fino a `targetSdk 36`: dal 37 l'app deve reggere
  anche l'orizzontale su schermo grande.
- Il test chiuso di Faraway è partito verso la revisione **senza** schermate
  dei tablet: la sezione tablet si può lasciare vuota.
- **«Elemento non trovato» dopo l'iscrizione al test chiuso**: il Play Store
  ci mette un po' (da qualche minuto a mezz'ora e oltre) ad accorgersi che un
  account è diventato tester. Configurazione, link e telefono possono essere
  tutti giusti: si riprova dopo. Sulla pagina /beta il passo 3 lo dice.
- **App a pagamento in test chiuso**: i tester la devono comprare, quindi si
  danno codici promozionali (Play Console > Promozioni, massimo 500 a
  trimestre) con il link `play.google.com/redeem?code=<codice>`, che apre il
  Play Store col codice già scritto. Finché Google non riconosce l'account come
  tester, il riscatto fallisce con **PRS-RPCPM-18**. Con Spot The Spy
  (25/09/2026) l'errore è rimasto anche con il tester già riconosciuto (il Play
  Store mostrava l'app «accesso in anteprima»): i codici nel test chiuso non
  sono affidabili. Soluzione usata: **saldo a 0 €** (Monetizza > Prezzo
  dell'app > Promozioni, tipo «Prezzo fisso» 0: la percentuale 100 non è
  accettata). Si può fare solo dopo che il test chiuso è pubblicato, dura al
  massimo 14 giorni, deve partire almeno dal giorno dopo e fra un saldo e
  l'altro servono 30 giorni.
  **Soluzione che funziona sempre**: aggiungere il gruppo Google dei tester in
  Play Console > Impostazioni > Test licenza > «Google Gruppi» (vale per tutte
  le app dell'account; la pagina carica lenta, e dopo «Salva modifiche» c'è una
  seconda conferma). Al tester il Play Store propone la «Carta di prova,
  approva sempre» e l'acquisto non costa niente (provato con Spot The Spy il
  25/09/2026). Lo suggerisce anche l'assistente di Google prima di aprire un
  ticket. Sulla pagina /beta va detto al tester di confermare solo se vede la
  carta di prova.
  Distributore dei codici per i tester: `_private/duebytes/beta/codice.php`.
- Il link del test interno (`play.google.com/apps/internaltest/...`) si apre
  solo da un Android con l'account della lista; subito dopo la prima
  pubblicazione può dare «Elemento non trovato» per un po'.
- **Schede tradotte** (Faraway, 26/09/2026): «Gestisci traduzioni» →
  «Seleziona lingue» (mai «Acquista traduzioni», è a pagamento). I campi
  riempiti da JavaScript risultano vuoti al controllo: serve un tasto vero in
  ciascuno (spazio e cancella). Una lingua nuova eredita le immagini di quella
  predefinita; per metterne di sue: caricarle nella libreria («Aggiungi asset»
  → Carica) con nomi distinti (`en-1.png`), poi per ogni lingua cercarle,
  freccia →, «Aggiungi», una alla volta nell'ordine. Vale anche per
  l'immagine in evidenza.
- Il questionario IARC ha una casella «Accetto i Termini»: la spunta Paolo.
- Creare il gruppo Google chiede un CAPTCHA: lo fa Paolo.

Expo (viste con Spot The Spy, 24/09/2026):
- **expo-audio accende l'audio in background da solo.** Il plugin ha
  `enableBackgroundPlayback` a `true` di default: su iOS mette
  `UIBackgroundModes: audio` (Apple rifiuta, linea guida 2.5.4, se l'app non
  suona niente in background), su Android aggiunge un servizio in primo piano
  `mediaPlayback` che Play Console vuole giustificato con un video. Se l'app
  usa l'audio solo con lo schermo acceso: `"enableBackgroundPlayback": false`
  nelle opzioni del plugin, e dopo il prebuild si controllano Info.plist e i
  permessi dell'APK.
- **`UIRequiresFullScreen` in `ios.infoPlist` non vale.** Expo lo riscrive a
  `false` e apre l'iPad a tutti gli orientamenti. Si usa
  `"requireFullScreen": true` dentro `expo.ios`.
- Su questo Mac Xcode non ha Simulator.app e il simulatore gira senza
  finestra. Per toccare lo schermo, sia su iOS sia su Android, c'è Maestro
  (`~/.maestro/bin/maestro`, con il JDK 17): istruzioni in
  `SpotTheSpy/docs/BUILD.md`.

Sul Mac:
- **Spostare le cartelle** delle app o delle chiavi rompe i percorsi assoluti:
  `<PREFISSO>_UPLOAD_STORE_FILE` in `~/.gradle/gradle.properties`, i remoti
  git fra NAS e clone locale in `~/dev/`, i documenti. Dopo uno spostamento si
  controllano tutti e tre.
- Faraway (Capacitor 8) compila Android con il **JDK 21**
  (`~/Library/Java/JavaVirtualMachines/jdk-21.0.12.1+1`), non col 17.
- La finestra di Chrome usata dall'estensione può ridursi a poche centinaia di
  pixel: si lavora in una tab nuova, che ha le dimensioni giuste.

## Cosa fa Paolo e cosa fa Claude

Claude prepara tutto e compila i moduli nel browser. Paolo fa quello che
Claude non può fare: password e accessi, CAPTCHA, dati bancari e documenti,
accettare contratti e condizioni, caricare file oltre i 10 MB. I pulsanti che
inviano o pubblicano (invia per la revisione, aggiungi alla verifica) li
preme Claude solo se Paolo lo dice in quel momento.

**Dopo l'invio tutto parte da solo** (regola di Paolo, 30/09/2026: non vuole
stare dietro alle approvazioni). Ogni app va impostata così:
- **App Store**: in ogni versione nuova, «Rilascia automaticamente questa
  versione» prima dell'invio alla verifica.
- **TestFlight**: la build si aggiunge al gruppo esterno prima di inviarla
  alla verifica beta, così appena Apple la approva arriva ai tester.
- **Google Play**: «Pubblicazione gestita» disattivata (Panoramica della
  pubblicazione). Così release di test, schede e immagini vanno online appena
  Google le approva.

**Note di versione** (App Store «Novità in questa versione», Play «Note di
rilascio»). Regola di Paolo, 01/10/2026: asciutte e tecniche, una riga per
cambiamento, solo quello che cambia nell'app per chi la usa. Esempi: «Corrette
le traduzioni», «Miglioramenti nell'interfaccia grafica», «Corretto il
calcolo dei Santuari». Mai le schede dello store o il lavoro interno, mai
seconda persona, mai frasi che iniziano con «E». Apple chiede solo di
descrivere le novità, i miglioramenti e le correzioni. Una volta pubblicata la
versione le note non si possono più cambiare: vanno scritte bene prima
dell'invio.

## Le indicazioni di Apple per le immagini dello store (lette il 28/09/2026)

Pagina: https://developer.apple.com/app-store/asset-best-practices/ (con
modelli per Figma, Photoshop, Pixelmator e Sketch).

- **Screenshot**: fino a 10; nei risultati di ricerca ne compaiono al massimo
  3, quindi le prime tre slide sono le più importanti. Interfaccia vera e
  attuale, frasi brevi che aggiungono qualcosa a ciò che si vede invece di
  descriverlo, niente prezzi, URL, simbolo ©, premi non ricevuti, loghi di
  altre piattaforme. Testi tradotti in ogni lingua dell'app.
- **Novità di iOS 27, «creative asset»**: l'**intestazione della pagina
  prodotto** (immagine o video, una sola idea chiara, pensata per chi non
  conosce l'app) e l'**immagine per i risultati di ricerca** (lo scopo
  dell'app a colpo d'occhio). Se mancano, nella ricerca si vedono gli
  screenshot. Si caricano con la versione nuova o dalla Libreria risorse.
- **Icona**: Apple consiglia Icon Composer (icone a strati per Liquid Glass,
  un solo disegno per iPhone, iPad, Mac e Watch), leggibile a ogni misura.
- **Video (app preview)**: facoltativi, fino a 3, interfaccia vera, partono
  muti e in loop.
