---
name: flutter-structure
description: Pipeline standalone di analisi strutturale per app Flutter Android. Scarica l'APK dal device via adb, decompila con jadx e blutter, e produce un report (in italiano) sull'anatomia dell'app: package Dart, plugin Flutter, SDK Android di terze parti, metriche quantitative (widget/route/state management), size breakdown dell'APK, hint su architettura e diagramma mermaid delle dipendenze tra package Dart. Invoca quando l'utente chiede "/flutter-structure" o dice di voler capire la struttura interna / mappare l'architettura / sapere cosa usa un'app Flutter Android installata.
---

# flutter-structure

Sei un operatore di analisi strutturale di app Flutter Android. Il tuo compito è produrre un report di "anatomia" dell'app: **come è organizzato il codice**, **che pacchetti usa**, **che SDK native include**, **con che architettura è scritto**. Non è un audit di sicurezza (per quello c'è la skill `reverse-apk`).

## Regole generali

- **Parla in italiano** in ogni output user-facing.
- **Output base fisso**: `~/Desktop/flutter-structure/<package_name>/`. Crealo se non esiste.
- **Solo Flutter**. Se l'app non è Flutter, fermati con messaggio chiaro e rimanda all'altra skill.
- **Chiedi conferma prima di installare tool** mancanti (via `brew` / `pip3`).
- **Gli script helper della skill** stanno in `~/.claude/skills/flutter-structure/scripts/`.
- **Non eseguire Frida**, non fare hooking runtime — la skill è statica.

## Step 1 — Preflight tool check

Esegui:
```bash
bash ~/.claude/skills/flutter-structure/scripts/check_tools.sh
```

Per ogni `MISS` mostrato, chiedi all'utente se vuole installarlo:

> Mancano questi tool: `<lista>`. Vuoi che li installi ora? [y/N]

Comandi di install (macOS):

| Tool | Comando |
|------|---------|
| `adb` | `brew install --cask android-platform-tools` |
| `python3` | `brew install python@3` |
| `jadx` | `brew install jadx` |
| `cmake`, `ninja`, `pkg-config`, `icu4c`, `capstone` | `brew install cmake ninja pkg-config icu4c capstone` |
| `pyelftools`, `requests` | `pip3 install --user pyelftools requests` |
| `unzip`, `git` | di sistema |
| `blutter` | `git clone https://github.com/worawit/blutter.git ~/Desktop/blutter` |

<warn>Su macOS Ventura/Sonoma la build di blutter richiede anche `brew install llvm@16`. Se la compilazione fallisce, suggerisci questo comando.</warn>

Ri-lancia `check_tools.sh` dopo l'install finché non torna `0`.

## Step 2 — Selezione dell'app

1. `adb devices -l` → se vuoto, chiedi di collegare device e riprova.

2. Chiedi all'utente:
   > Qual è il package dell'app Flutter che vuoi analizzare?

3. Se la risposta non è un package completo, cerca:
   ```bash
   adb shell pm list packages | grep -i '<keyword>'
   ```
   Mostra le corrispondenze numerate, fai scegliere. Se c'è un solo match, conferma prima di procedere.

4. Salva come `<package>`.

## Step 3 — Cartella di lavoro

```bash
OUT="$HOME/Desktop/flutter-structure/<package>"
mkdir -p "$OUT"/{apks,source,split_arm64,blutter_out,analysis,report}
cd "$OUT"
```

Struttura finale:
```
~/Desktop/flutter-structure/<package>/
├── apks/              # split APK scaricati dal device
├── source/            # jadx output (Java/Kotlin lato Android)
├── split_arm64/       # contenuto estratto di split_config.arm64_v8a.apk
├── blutter_out/       # blutter output (pp.txt, asm/, objs.txt, blutter_frida.js)
├── analysis/          # intermediate files: package_list.txt, plugins.txt, sdk_list.txt, metrics.txt, sizes.txt
└── report/
    └── REPORT.md      # report finale
```

## Step 4 — Pull degli APK

```bash
adb shell pm path <package>
```

Scarica tutti gli split in `$OUT/apks/`:
```bash
adb pull <remote_path> "$OUT/apks/"
```

Se mancano split arm64 → l'app è solo 32-bit → **stop**: blutter non può processarla, informa l'utente.

## Step 5 — Verifica che sia Flutter

Hard check:
```bash
is_flutter=0
if [ -f "$OUT/apks/split_config.arm64_v8a.apk" ]; then
  unzip -l "$OUT/apks/split_config.arm64_v8a.apk" | grep -qE 'lib/arm64-v8a/libflutter\.so' && is_flutter=1
fi
if [ $is_flutter -eq 0 ] && [ -f "$OUT/apks/base.apk" ]; then
  unzip -l "$OUT/apks/base.apk" | grep -qE 'lib/arm64-v8a/libflutter\.so' && is_flutter=1
fi
```

Se `is_flutter=0`: **stop** e mostra:

> ❌ Questa app non è Flutter (manca `libflutter.so`).
> Questa skill analizza solo app Flutter. Per app native usa `/reverse-apk` che fa anche l'analisi di app Java/Kotlin, oppure consulta la guida "Reverse engineering di app Android native" su Notion.

## Step 6 — Decompilazione

### 6a — jadx sul base.apk

```bash
jadx apks/base.apk -d source/ 2>&1 | tail -20
```

### 6b — Estrazione + blutter

```bash
unzip -o apks/split_config.arm64_v8a.apk -d split_arm64/ > /dev/null
# Se single-APK (base.apk contiene le librerie):
[ ! -d split_arm64/lib/arm64-v8a ] && unzip -o apks/base.apk -d split_arm64/ > /dev/null

BLUTTER=~/Desktop/blutter  # se diverso, adatta
cd "$BLUTTER"
python3 blutter.py "$OUT/split_arm64/lib/arm64-v8a" "$OUT/blutter_out"
cd "$OUT"
```

<warn>Prima esecuzione per una nuova versione Dart: 30+ min (build del Dart SDK). Mostra l'attesa all'utente.</warn>

Verifica: `blutter_out/pp.txt` e `blutter_out/objs.txt` devono esistere e non essere vuoti.

## Step 7 — Estrazione dati strutturali

Leggi `~/.claude/skills/flutter-structure/scripts/patterns.md` per i pattern esatti da usare.

Tutti gli output intermedi vanno in `$OUT/analysis/`.

### 7a — Package Dart tree

Estrai URI `package:foo/bar.dart` da `blutter_out/pp.txt`:

```bash
grep -oE 'package:[a-zA-Z0-9_./-]+' blutter_out/pp.txt | sort -u > analysis/all_packages.txt
awk -F'[:/]' '{print $2}' analysis/all_packages.txt | sort -u > analysis/package_names.txt
# Conta le librerie per package
awk -F'[:/]' '{pkg=$2; count[pkg]++} END {for (p in count) print count[p], p}' analysis/all_packages.txt | sort -rn > analysis/package_counts.txt
```

Distingui:
- **App code** → package che coincide con il nome dell'app (es. `my_app`), di solito 1-2 package
- **Flutter SDK** → `flutter`, `flutter_test`, `flutter_web_plugins`, `sky_engine`
- **Dart SDK** → nomi come `dart:core`, `dart:io`, `dart:async` (prefisso `dart:`, non `package:`)
- **Terze parti** → tutto il resto

### 7b — Plugin Flutter installati

I plugin Flutter si registrano in `GeneratedPluginRegistrant.java` o `GeneratedPluginRegistrant.kt` (lato Android). Decompilati da jadx stanno in:
```bash
find source -name 'GeneratedPluginRegistrant*' 2>/dev/null
```

Estrai le classi `*Plugin` registrate:
```bash
grep -hE 'new [A-Za-z0-9_]+Plugin\(\)|import .*\.[A-Za-z0-9_]+Plugin;' \
  $(find source -name 'GeneratedPluginRegistrant*') 2>/dev/null \
  | grep -oE '[a-z0-9_]+\.[A-Za-z0-9_.]+Plugin' \
  | sort -u > analysis/flutter_plugins.txt
```

In aggiunta, cerca i nomi di plugin comuni nel package list del 7a (es. `url_launcher`, `shared_preferences`, `path_provider`, `firebase_core`, `google_maps_flutter`, `connectivity_plus`, ecc.).

### 7c — SDK Android lato Java

Pattern matching su `source/sources/` per package noti. Lista dei prefissi in `patterns.md` sezione "SDK Android noti". Esempio:

```bash
for prefix in \
  "com/google/firebase" \
  "io/sentry" \
  "com/onesignal" \
  "com/stripe" \
  "com/segment" \
  "com/amplitude" \
  "com/mixpanel" \
  "com/appsflyer" \
  "com/adjust" \
  "com/braze" \
  "com/datadog" \
  "com/newrelic" \
  "com/fullstory" \
  "com/revenuecat" \
  "io/branch" \
  "com/facebook/react" \
  "com/google/android/gms" \
  "com/google/android/play" \
  "androidx/biometric" \
  "androidx/security" ; do
  if [ -d "source/sources/$prefix" ]; then
    count=$(find "source/sources/$prefix" -name '*.java' 2>/dev/null | wc -l | tr -d ' ')
    echo "$count $prefix" >> analysis/sdk_android.txt
  fi
done
sort -rn analysis/sdk_android.txt -o analysis/sdk_android.txt
```

### 7d — Metriche quantitative

```bash
# Widget count (euristica sull'output blutter)
grep -cE ' : (StatelessWidget|StatefulWidget|ConsumerWidget|HookWidget)' blutter_out/objs.txt > analysis/widget_count.txt

# Route (navigazione)
grep -oE '[A-Za-z0-9_]+Page|[A-Za-z0-9_]+Screen|[A-Za-z0-9_]+Route' blutter_out/pp.txt | sort -u | wc -l > analysis/route_count.txt

# State management (match su nomi package)
SM_LIBS=""
for lib in flutter_bloc bloc cubit provider riverpod flutter_riverpod hooks_riverpod get getx mobx redux flutter_redux; do
  grep -qxF "package:$lib" analysis/all_packages.txt 2>/dev/null && SM_LIBS="$SM_LIBS $lib"
done
echo "State management rilevato:$SM_LIBS" > analysis/state_mgmt.txt

# Asset count
find split_arm64 -path '*flutter_assets*' -type f 2>/dev/null | wc -l > analysis/asset_count.txt

# Font asset
find split_arm64 -path '*flutter_assets/fonts*' -type f 2>/dev/null > analysis/fonts.txt

# Stringhe localizzate (Flutter: AssetManifest.json + intl_* files)
find split_arm64 -path '*flutter_assets*' -name 'intl_*.arb' 2>/dev/null > analysis/locales.txt
# Fallback Flutter moderno: l10n arb
find source -name '*.arb' 2>/dev/null >> analysis/locales.txt
```

### 7e — Size breakdown

```bash
# Size totale APK
du -h apks/ | tail -1 > analysis/apk_total_size.txt

# Top 20 file più grossi nel bundle (tutti gli split estratti)
unzip -o -q apks/base.apk -d analysis/base_unpacked/ 2>/dev/null
find analysis/base_unpacked split_arm64 -type f 2>/dev/null \
  -exec du -h {} \; | sort -rh | head -20 > analysis/top_files.txt

# Size di libapp.so (il codice Dart AOT dell'app stessa)
[ -f split_arm64/lib/arm64-v8a/libapp.so ] && du -h split_arm64/lib/arm64-v8a/libapp.so > analysis/libapp_size.txt

# Size di flutter_assets
du -sh analysis/base_unpacked/assets/flutter_assets/ 2>/dev/null > analysis/flutter_assets_size.txt

# Size totale lib/arm64-v8a
du -sh split_arm64/lib/arm64-v8a/ 2>/dev/null > analysis/native_size.txt
```

### 7f — Hint su architettura

Scansiona i **nomi delle cartelle** in `source/sources/` (Android side) e i **segmenti di path** di `blutter_out/pp.txt` (Dart side).

Pattern → indizio (vedi `patterns.md`):
- Presenza di cartelle `bloc/`, `cubit/` → **BLoC pattern**
- Presenza di `usecase/`, `repository/`, `datasource/`, `domain/`, `data/`, `presentation/` → **Clean Architecture**
- Presenza di `features/<feature_name>/` multipli → **Feature-first**
- Presenza di `screens/`, `views/`, `pages/` → **UI-first / MVC**
- Presenza di `providers/` + package `provider`/`riverpod` → **Provider / Riverpod pattern**

Salva gli hint trovati in `analysis/arch_hints.txt`.

### 7g — Diagramma mermaid dipendenze Dart

Per ogni package Dart terzo (escludendo Flutter SDK, Dart SDK e app stessa), estrai chi importa chi. Nota: `blutter` non preserva gli import originali, ma dai nomi dei campi/classi in `objs.txt` è possibile stimare grossolanamente le dipendenze "di chiamata". Per stare sul semplice, genera un grafo dove l'app code punta ai top-10 package più usati:

```bash
cat > analysis/dependency_graph.mmd <<EOF
graph LR
    app[<app_package>]
EOF
head -10 analysis/package_counts.txt | awk '{print "    app --> "$2}' | sed 's/[^a-zA-Z0-9_. ->[\]]//g' >> analysis/dependency_graph.mmd
```

Se l'utente ha scelto l'opzione "diagramma mermaid" in fase di discussione, includi il `.mmd` nel report dentro un blocco ` ```mermaid `. Altrimenti omettilo.

## Step 8 — Generazione report

Usa `~/.claude/skills/flutter-structure/scripts/report_template.md` come scheletro. Compila i placeholder con i dati raccolti in `analysis/`. Salva il risultato in `$OUT/report/REPORT.md`.

Il report include tutte e 4 le sezioni (selezionate dall'utente in fase di discussione):
1. Dart package tree + Flutter plugin
2. SDK Android lato Java
3. Metriche quantitative + size breakdown
4. Hint architettura + diagramma mermaid

## Step 9 — Chiusura

Mostra all'utente:
- Path completo del report
- Headline numerici: "N° package Dart: X · Plugin Flutter: Y · SDK Android: Z · App size: W MB"
- 3 insight notevoli emersi dall'analisi (es: "usa Riverpod + Clean Architecture", "Firebase + Sentry + AppsFlyer integrati", "libapp.so = 15 MB ⇒ app molto grande", ecc.)
- Invita a confrontare con la skill `/reverse-apk` se vuole anche audit sicurezza

Checklist finale:
- [ ] APK scaricati
- [ ] Verifica Flutter OK
- [ ] jadx completato
- [ ] blutter completato
- [ ] 4 sezioni di analisi popolate
- [ ] Report salvato in `report/REPORT.md`

## Gestione errori comuni

- **App non Flutter** → stop con messaggio chiaro (step 5)
- **blutter fallisce build** → mostra ultime 30 righe log, suggerisci `brew install llvm@16` su macOS <15
- **Nessun plugin trovato in GeneratedPluginRegistrant** → potrebbe essere app senza plugin (raro) o Flutter < 1.9 (vecchio registration) → fall back a ricerca generica di classi che implementano `FlutterPlugin`
- **pp.txt vuoto o troncato** → blutter non è riuscito a leggere lo snapshot; verifica versione Dart supportata
- **Size breakdown vuoto** → non hai estratto il base.apk; rilancia lo step 7e
