# App con Capacitor: una PWA dentro iOS e Android

Il percorso fatto con Faraway Score (settembre 2026): Capacitor 8.5 attorno a
una PWA in HTML, CSS e JS senza framework (`webDir: "pwa"`). Una sola base di
codice per il sito e per le due app. Quanto Basta invece è Expo / React Native:
per quella vale il suo repository.

Il dettaglio di Faraway è in `Faraway/docs/app-native.md`. Qui c'è quello che
vale per qualunque app fatta così.

## Quando sceglierlo

Va bene per un'app semplice che deve girare **anche come sito**: le app native
servono gli stessi file del web. Conviene meno se servono tante funzioni native
o un aspetto nativo vero (allora Expo). Il limite da tenere presente: quando
l'app va in background il JavaScript si ferma. Quello che deve succedere "dopo",
come un timer che suona, va affidato a una notifica locale programmata prima.

## Dove si compila

**Mai dal NAS**: su SMB Xcode, Gradle e la CLI di Vercel falliscono con
«disk I/O error», «Bad file descriptor» o EBADF. Clone locale in
`~/dev/<app>`: si modifica e si committa sul NAS, nel clone si fa
`git pull --no-rebase` e poi `npx cap copy`. Sul NAS il remoto `locale` punta
al clone. `gradlew` su SMB perde il permesso di esecuzione:
`git update-index --chmod=+x android/gradlew`.

## Trappole già pagate

- **Caratteri**: nella WebView (`capacitor://localhost`) Google Fonts non
  arriva. I caratteri vanno dentro l'app (woff2 da @fontsource), mai con un
  `@import` remoto.
- **Splash bianca**: `@capacitor/splash-screen` con `launchAutoHide: false`,
  poi `SplashScreen.hide()` da JS dopo il primo disegno (e comunque dopo 3 s).
  Su Android 12+ la splash la disegna il sistema: `windowSplashScreenBackground`
  e `windowSplashScreenAnimatedIcon` nello stile `AppTheme.NoActionBarLaunch`.
- **Icone**: mai `@capacitor/assets`, riscrive le icone Android. Meglio uno
  script (Pillow) che le genera tutte. Icona adattiva Android con fondo a tinta
  piena e disegno dentro la zona sicura; su iOS il disegno all'84% circa.
- **Indietro.** Se le schermate non passano dalla cronologia, su iPhone lo
  swipe dal bordo non fa niente e su Android il tasto indietro **chiude l'app**.
  Serve tutto e tre:
  1. in JS, `history.pushState` per ogni schermata, a livelli, e un gestore di
     `popstate` che chiude fogli e fotocamera e mostra la schermata;
  2. iOS: una sottoclasse di `CAPBridgeViewController` con
     `webView?.allowsBackForwardNavigationGestures = true` in
     `capacitorDidLoad()`, usata come `rootViewController` in `SceneDelegate`;
  3. Android: un `OnBackPressedCallback` in `MainActivity` che fa
     `webView.goBack()` se `canGoBack()`, altrimenti lascia chiudere.
- **Solo verticale**: su iPad `UIRequiresFullScreen`; su Android 16 con
  targetSdk 36 `screenOrientation` è ignorato su tablet e pieghevoli e serve
  la property `android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY`.
- **JDK 21** per Android (col 17: «invalid source release: 21»).
- Xcode 27: `npx cap run ios` non trova il simulatore. Si compila con
  `xcodebuild` e si installa con `xcrun simctl install` / `launch`.
- **Audio** nella WKWebView: parte solo dopo un gesto dell'utente, va
  "sbloccato" al primo tocco.
- **Fotocamera**: `getUserMedia` funziona nella WebView con
  `NSCameraUsageDescription` (iOS) e il permesso `CAMERA` (Android). Il
  simulatore iOS non ha la fotocamera.

## Build per gli store

Comandi e firme in `pubblicare.md`. In breve: iOS `xcodebuild archive` +
`-exportArchive` con `comune/ios/ExportOptions.plist`; Android
`./gradlew bundleRelease` con la chiave di caricamento in
`~/.gradle/gradle.properties`.
