[{"data":1,"prerenderedAt":27},["ShallowReactive",2],{"articolo-flutter-su-wear-os-creare-app-per-smartwatch-android":3,"comments-article-flutter-su-wear-os-creare-app-per-smartwatch-android":26},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"status":16,"published_at":17,"meta_title":18,"meta_description":19,"category":20,"author":24},130,"Flutter su Wear OS: creare app per smartwatch Android","flutter-su-wear-os-creare-app-per-smartwatch-android","Flutter non gira solo su telefoni: con qualche accortezza nel manifest e i pacchetti giusti si possono costruire app per Wear OS. Guida pratica a schermi rotondi, ambient mode, input rotativo e comunicazione con lo smartphone.","## Perché Wear OS con Flutter\n\nWear OS è a tutti gli effetti Android, quindi il motore Flutter ci gira senza modifiche al framework: una build `android` standard viene installata ed eseguita sull'orologio. Quello che cambia è il **contesto d'uso**: schermi da 1,2\" a 1,5\" (spesso rotondi), interazioni di pochi secondi, batteria ridotta, input rotativo e una modalità a basso consumo (*ambient*) in cui il display resta acceso ma deve consumare pochissimo.\n\nIn questa guida vediamo come configurare un progetto Flutter per Wear OS, adattare la UI alla forma dello schermo, gestire l'ambient mode, supportare la corona\u002Fbezel rotativo e scambiare dati con l'app companion sul telefono.\n\n## Configurare il progetto Android\n\nPartiamo da un normale progetto Flutter e interveniamo sulla parte Android.\n\n### AndroidManifest.xml\n\nIl manifest deve dichiarare che l'app è destinata a un dispositivo indossabile e che funziona in modo **standalone** (cioè senza richiedere obbligatoriamente l'app sul telefono):\n\n```xml\n\u003Cmanifest xmlns:android=\"http:\u002F\u002Fschemas.android.com\u002Fapk\u002Fres\u002Fandroid\">\n\n    \u003Cuses-feature android:name=\"android.hardware.type.watch\" \u002F>\n    \u003Cuses-permission android:name=\"android.permission.WAKE_LOCK\" \u002F>\n\n    \u003Capplication\n        android:label=\"wear_demo\"\n        android:icon=\"@mipmap\u002Fic_launcher\">\n\n        \u003C!-- true = l'app funziona anche senza companion sullo smartphone -->\n        \u003Cmeta-data\n            android:name=\"com.google.android.wearable.standalone\"\n            android:value=\"true\" \u002F>\n\n        \u003Cuses-library\n            android:name=\"com.google.android.wearable\"\n            android:required=\"false\" \u002F>\n\n        \u003Cactivity\n            android:name=\".MainActivity\"\n            android:exported=\"true\"\n            android:launchMode=\"singleTop\"\n            android:theme=\"@style\u002FLaunchTheme\"\n            android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|uiMode|density\"\n            android:hardwareAccelerated=\"true\"\n            android:windowSoftInputMode=\"adjustResize\">\n            \u003Cintent-filter>\n                \u003Caction android:name=\"android.intent.action.MAIN\" \u002F>\n                \u003Ccategory android:name=\"android.intent.category.LAUNCHER\" \u002F>\n            \u003C\u002Fintent-filter>\n        \u003C\u002Factivity>\n    \u003C\u002Fapplication>\n\u003C\u002Fmanifest>\n```\n\n### build.gradle\n\nWear OS 3 e successivi richiedono API 30; se vuoi coprire anche i vecchi Wear OS 2 puoi scendere a 25, ma la maggior parte del parco installato oggi è su 3\u002F4\u002F5.\n\n```kotlin\nandroid {\n    namespace = \"com.example.wear_demo\"\n    compileSdk = 35\n\n    defaultConfig {\n        applicationId = \"com.example.wear_demo\"\n        minSdk = 30        \u002F\u002F Wear OS 3+\n        targetSdk = 35\n    }\n}\n\ndependencies {\n    implementation(\"androidx.wear:wear:1.3.0\")\n}\n```\n\nUn dettaglio spesso dimenticato: imposta lo sfondo della finestra di avvio su **nero**. Su un display OLED di un orologio uno splash bianco è fastidioso e consuma di più. Modifica `android\u002Fapp\u002Fsrc\u002Fmain\u002Fres\u002Fvalues\u002Fstyles.xml` e la variante `values-night`.\n\n## Adattare la UI allo schermo dell'orologio\n\nIl pacchetto di riferimento è [`wear_plus`](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fwear_plus), erede del vecchio `wear`:\n\n```yaml\ndependencies:\n  wear_plus: ^1.3.0\n```\n\nEspone tre strumenti fondamentali: `WatchShape` (forma dello schermo), `AmbientMode` (modalità a basso consumo) e `InheritedShape`.\n\n```dart\nimport 'package:flutter\u002Fmaterial.dart';\nimport 'package:wear_plus\u002Fwear_plus.dart';\n\nclass WatchApp extends StatelessWidget {\n  const WatchApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(\n        brightness: Brightness.dark,\n        scaffoldBackgroundColor: Colors.black,\n        useMaterial3: true,\n      ),\n      home: WatchShape(\n        builder: (context, shape, child) {\n          final isRound = shape == WearShape.round;\n          return Padding(\n            \u002F\u002F su schermo rotondo gli angoli non sono utilizzabili\n            padding: EdgeInsets.all(isRound ? 24 : 12),\n            child: child!,\n          );\n        },\n        child: const HomeScreen(),\n      ),\n    );\n  }\n}\n```\n\nLinee guida pratiche per la UI:\n\n- **Sfondo nero**: sui pannelli OLED i pixel neri sono spenti, quindi è una scelta di design *e* di autonomia.\n- **Un'informazione per schermata**: niente dashboard, niente tabelle. Testo grande, target touch da almeno 48dp.\n- **Niente AppBar classica**: lo spazio verticale è prezioso; usa un titolo in cima alla lista che scorre via.\n- **Attenzione agli angoli**: su schermo rotondo il contenuto va inscritto in un cerchio, con padding generoso.\n- **Evita input testuali**: la tastiera su un orologio è un'esperienza pessima; preferisci scelte predefinite o dettatura vocale.\n\n## Input rotativo: corona e bezel\n\nQuasi tutti gli orologi Wear OS hanno una corona rotante o un bezel. Il motore Flutter traduce questi eventi in **pointer scroll**, quindi un `ListView` con `ScrollController` reagisce già di suo. Per aggiungere la classica scrollbar curva laterale che compare durante la rotazione, il pacchetto [`rotary_scrollbar`](https:\u002F\u002Fpub.dev\u002Fpackages\u002Frotary_scrollbar) è la soluzione più rapida:\n\n```dart\nclass RotaryList extends StatefulWidget {\n  const RotaryList({super.key});\n\n  @override\n  State\u003CRotaryList> createState() => _RotaryListState();\n}\n\nclass _RotaryListState extends State\u003CRotaryList> {\n  final _controller = ScrollController();\n\n  @override\n  void dispose() {\n    _controller.dispose();\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return RotaryScrollbar(\n      controller: _controller,\n      child: ListView.builder(\n        controller: _controller,\n        padding: const EdgeInsets.symmetric(vertical: 32),\n        itemCount: 20,\n        itemBuilder: (context, index) => ListTile(\n          title: Text('Elemento $index'),\n          onTap: () {},\n        ),\n      ),\n    );\n  }\n}\n```\n\nSe usi un `PageView` verticale, imposta `pageSnapping: true` e una `ScrollPhysics` che renda lo snap deciso: sull'orologio la navigazione a \"schede\" verticali è il pattern più naturale.\n\n## Ambient mode: l'app sempre visibile\n\nQuando l'utente abbassa il polso, Wear OS porta l'app in **ambient mode**: lo schermo resta acceso ma il sistema si aspetta una UI monocromatica, con pochi pixel accesi e aggiornamenti al massimo una volta al minuto.\n\n```dart\nimport 'package:intl\u002Fintl.dart';\n\nclass HomeScreen extends StatelessWidget {\n  const HomeScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return AmbientMode(\n      builder: (context, mode, child) {\n        final isAmbient = mode == WearMode.ambient;\n        return Container(\n          color: Colors.black,\n          alignment: Alignment.center,\n          child: Column(\n            mainAxisAlignment: MainAxisAlignment.center,\n            children: [\n              Text(\n                DateFormat('HH:mm').format(DateTime.now()),\n                style: TextStyle(\n                  fontSize: 40,\n                  \u002F\u002F in ambient: solo grigio chiaro, niente colori saturi\n                  color: isAmbient ? Colors.white70 : Colors.tealAccent,\n                  fontWeight: isAmbient ? FontWeight.w300 : FontWeight.bold,\n                ),\n              ),\n              if (!isAmbient) ...[\n                const SizedBox(height: 8),\n                const Text('Tocca per iniziare'),\n              ],\n            ],\n          ),\n        );\n      },\n    );\n  }\n}\n```\n\nRegole d'oro per l'ambient:\n\n1. **Stoppa animazioni, timer e stream**: in ambient ogni frame costa batteria. Se hai un `Ticker`, mettilo in pausa.\n2. **Niente aree bianche piene**: usa testo sottile su nero.\n3. **Aggiorna al massimo ogni minuto**: Flutter non riceve il tick di sistema \"ambient update\" senza codice nativo; in pratica conviene ridisegnare solo sui cambi di stato.\n4. Valuta se l'always-on serve davvero: per molte app è meglio lasciare che lo schermo si spenga.\n\n## Parlare con lo smartphone\n\nMolte app orologio sono un satellite di un'app sul telefono. Per scambiare messaggi e stato si usa la Data Layer API di Wear OS, esposta a Dart dal pacchetto [`watch_connectivity`](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fwatch_connectivity) (che su iOS copre anche watchOS, utile se hai già un'app companion):\n\n```dart\nimport 'package:watch_connectivity\u002Fwatch_connectivity.dart';\n\nclass WatchBridge {\n  final _watch = WatchConnectivity();\n\n  Future\u003Cbool> get isReady async =>\n      await _watch.isSupported && await _watch.isPaired;\n\n  \u002F\u002F\u002F Messaggi \"fire and forget\", richiedono che il peer sia raggiungibile.\n  Future\u003Cvoid> inviaComando(String azione) async {\n    if (await _watch.isReachable) {\n      await _watch.sendMessage({'action': azione, 'ts': DateTime.now().toIso8601String()});\n    }\n  }\n\n  \u002F\u002F\u002F Stato condiviso e persistente: viene sincronizzato appena possibile.\n  Future\u003Cvoid> aggiornaStato(Map\u003CString, dynamic> stato) =>\n      _watch.updateApplicationContext(stato);\n\n  Stream\u003CMap\u003CString, dynamic>> get messaggi => _watch.messageStream;\n}\n```\n\nIn generale: usa `sendMessage` per azioni immediate (es. \"metti in pausa la riproduzione\") e `updateApplicationContext` per sincronizzare lo stato (es. token, preferenze, ultimo valore noto), perché viene consegnato anche se il peer è temporaneamente offline.\n\nSe invece l'orologio ha connettività autonoma (Wi-Fi o LTE), progetta l'app come **standalone**: chiama direttamente le tue API e tieni una cache locale, evitando di dipendere dal telefono.\n\n## Permessi, sensori e salute\n\nSull'orologio sono particolarmente rilevanti:\n\n- **Battito cardiaco e sensori corporei**: richiedono `BODY_SENSORS` (e `BODY_SENSORS_BACKGROUND` per l'uso in background). Dal lato Flutter si accedono tramite platform channel o pacchetti dedicati come `health`.\n- **Posizione**: il GPS dell'orologio consuma molto; usa `geolocator` con accuratezza ridotta quando non serve il massimo.\n- **Vibrazione**: usa `HapticFeedback.lightImpact()` sui tap, sull'orologio è il feedback principale.\n\n## Limiti da conoscere prima di partire\n\nFlutter copre bene la **schermata dell'app**, ma non tutte le superfici di Wear OS:\n\n- **Tiles e Complications** (le schede scorrevoli e i widget sul quadrante) devono essere scritte in Kotlin con ProtoLayout: non sono renderizzate dal motore Flutter. Puoi comunque convivere, aggiungendo un modulo nativo al progetto Android.\n- **Watch face**: stesso discorso, serve l'API nativa Watch Face Format.\n- **Dimensione dell'APK**: il motore Flutter pesa qualche MB; su un orologio con storage limitato conviene usare `--split-per-abi` o un App Bundle e rimuovere asset e font inutilizzati.\n- **Memoria e GPU**: gli orologi hanno hardware modesto. Evita blur, ombre pesanti e liste con molte immagini; Impeller aiuta, ma la frugalità resta la regola.\n\n## Build, test e pubblicazione\n\nPer lo sviluppo puoi usare l'emulatore Wear OS incluso in Android Studio (Device Manager → categoria Wear OS, scegli una forma rotonda per testare davvero il layout) oppure un orologio fisico con debug ADB via Wi-Fi.\n\n```bash\nflutter devices\nflutter run -d \u003Cid-emulatore-wear>\nflutter build appbundle --release\n```\n\nSull'emulatore puoi simulare l'ambient mode con:\n\n```bash\nadb shell am broadcast -a com.google.android.wearable.action.ENTER_AMBIENT\nadb shell am broadcast -a com.google.android.wearable.action.EXIT_AMBIENT\n```\n\nPer la pubblicazione hai due strade: un'app **standalone** con un proprio `applicationId` e una scheda Play dedicata al form factor Wear OS, oppure un'app distribuita insieme a quella mobile (stesso package, APK multipli). Nella Play Console dovrai dichiarare il supporto a Wear OS e superare la review sulle linee guida di qualità specifiche: avvio rapido, nessun testo tagliato sullo schermo rotondo, gestione corretta dell'ambient e assenza di riferimenti a interazioni \"da telefono\".\n\n## Conclusioni\n\nPortare Flutter su Wear OS è tecnicamente semplice — il grosso del lavoro è di **design**. Configura il manifest per il form factor watch, usa `wear_plus` per forma e ambient mode, supporta la corona rotante, riduci la UI all'essenziale e decidi fin dall'inizio se l'app è standalone o companion. Con queste basi puoi riutilizzare la logica di dominio dell'app mobile e aggiungere una superficie al polso con uno sforzo contenuto.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002Fa4baa02a-623c-40f7-a8da-389a73b4ce33.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1646738004106-88ecc987e229?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3OTIyMDk3MTh8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Csaba Bakos","https:\u002F\u002Funsplash.com\u002F@ch4nc3","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-close-up-of-a-watch-near-a-keyboard-6hfME9wXI1w",null,"published","2026-10-17T04:01:59+00:00","Flutter su Wear OS: guida alle app per smartwatch","Come creare app Flutter per Wear OS: configurazione del manifest, schermi rotondi, ambient mode, input rotativo e comunicazione con lo smartphone.",{"id":21,"name":22,"slug":23},1,"Guide","guide",{"id":21,"name":25},"Flutter Bot",[],1792316897318]