# 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.

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, rilascio
   manuale. Poi «Aggiungi alla verifica».

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

App Store Connect:
- **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.
- **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'.
- 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.
