Android & Flutter Resource Cleaner — VS Code Extension
Detects unused drawables, strings, layouts, colors, and Flutter assets in a project,
shows potential storage savings, and lets you clean them up with one click.
How it works
- Android detection: scans every
res/ directory in the project, indexes
file-based resources (drawables, mipmaps, layouts, menus, anims, raw, fonts) and
value-based resources declared inside res/values/*.xml (strings, colors, dimens,
styles). It then searches all .kt, .java, and .xml source for R.<type>.<name>
and @<type>/<name> references. Anything with zero references is flagged as unused.
- Flutter detection: parses
pubspec.yaml for declared assets: and fonts:
entries (including whole-folder references), then searches all .dart source for
the exact asset path string. Anything unreferenced is flagged.
- Confidence levels:
high (file-based resource, zero references anywhere),
medium (value-type resource — could theoretically be referenced indirectly via a
style/theme chain we don't fully resolve), low (the codebase uses dynamic
construction like getIdentifier() or Dart string interpolation near a matching
path, so we can't be statically certain). Low-confidence items are never
default-checked.
Setup
cd vscode-extension
npm install
npm run compile
Running it in the Extension Development Host (for testing without publishing)
- Open the
vscode-extension folder in VS Code.
- Press
F5 (or Run → Start Debugging). This launches a second VS Code window
("Extension Development Host") with the extension loaded.
- In that new window, open any Android or Flutter project folder.
- Run the command "Resource Cleaner: Scan Project" from the Command Palette
(
Cmd/Ctrl+Shift+P), or right-click a folder in the Explorer.
- Click Scan Project in the panel, review the grouped checklist, then click
Clean Selected.
Packaging as a real, installable .vsix
npm install -g @vscode/vsce
vsce package
This produces a resource-cleaner-0.1.0.vsix file. Install it in any VS Code (or
Android Studio, if you later build the IntelliJ port — see below) via:
code --install-extension resource-cleaner-0.1.0.vsix
or through the Extensions panel's "Install from VSIX…" option.
Safety design choices worth knowing about
- File-based resources (drawables, layouts, Flutter assets) are deleted via
vscode.workspace.fs.delete with useTrash: true — they go to your OS trash/recycle
bin, not a permanent unlink, so they're recoverable if something was a false positive.
- Value-type resources (a
<string> entry inside strings.xml, for example) can't be
"trashed" individually since they're one node inside a shared file. Removing them
means parsing the XML, dropping the matching node, and rewriting the file. This is
not trash-recoverable the same way — the confirmation dialog says so explicitly,
and recommends having a clean git working tree before cleaning these.
- Low-confidence items (dynamic lookups, string-interpolated paths) are listed but
unchecked by default. You have to deliberately opt in to deleting those.
Project structure
vscode-extension/
├── src/
│ ├── reportSchema.ts # Shared types for the unused-resource report
│ ├── fsUtils.ts # Directory walking, byte formatting, etc.
│ ├── androidDetector.ts # Android res/ scanning + reference search
│ ├── flutterDetector.ts # pubspec.yaml asset scanning + reference search
│ ├── scanner.ts # Orchestrates both detectors into one grouped report
│ ├── cleaner.ts # Performs the actual delete / XML rewrite
│ ├── panel.ts # Webview panel controller (extension host side)
│ └── extension.ts # Command registration / activation
└── media/
├── main.js # Webview UI logic (runs inside the webview, not Node)
├── main.css
└── icon.svg
Known limitations (be upfront with users about these)
- Dynamic resource construction (
getIdentifier() in Android, string interpolation
in Dart) can't be perfectly resolved statically — those cases are flagged low-confidence
rather than silently treated as either used or unused.
- Resources referenced only from Gradle/build config, or from other modules not scanned
(e.g. a separate library module outside the project root passed to the scanner), can
produce false positives. Scan from the actual top-level project root.
- The XML rewrite for value-type resources reformats the whole file (via a parse +
rebuild), so unrelated formatting/whitespace may shift even though content is preserved.
Next steps (not built yet)
- IntelliJ/Android Studio plugin sharing this same detection logic (ported to
Kotlin) and reusing this same JSON report schema + webview HTML/CSS, per the
architecture discussed.
- Optional:
flutter_gen strongly-typed asset detection, .arb localization key
usage detection, unused Dart class/widget detection.
| |