| name | shortcut-anything |
| description | Decompile Android APK/XAPK and extract deeplinks, shortcuts, share APIs with ADB validation. Use this skill whenever the user mentions: analyzing an APK, extracting deeplinks or deep links, decompiling Android apps, finding app shortcuts, reverse engineering APK/XAPK, smali analysis, ADB validation of URIs, batch processing multiple APKs, or wants to know what intents/URIs an Android app supports. Trigger even if the user just drops an APK filename or says things like 'ๅธฎๆๅๆ่ฟไธชAPK'ใ'ๆๅdeeplink'ใ'ๅ็ผ่ฏ'ใ'ๅฟซๆทๆนๅผๆๅ'. |
| license | Apache-2.0 |
| compatibility | opencode |
Locating SKILL_DIR: Before running any tool, resolve SKILL_DIR with the command below. Use absolute paths for all subsequent tool calls.
SKILL_DIR=$(python3 -c "
import pathlib, sys
candidates = [
pathlib.Path.home() / '.config/opencode/skills/shortcut-anything',
pathlib.Path.home() / '.claude/skills/shortcut-anything',
pathlib.Path.home() / '.codex/skills/shortcut-anything',
pathlib.Path.home() / '.hermes/openclaw-imports/shortcut-anything',
pathlib.Path.home() / '.openclaw/workspace/skills/shortcut-anything',
]
for c in candidates:
if (c / 'SKILL.md').exists():
print(c); sys.exit(0)
sys.exit(1)
")
echo "SKILL_DIR=$SKILL_DIR"
If the exit code is non-zero, the skill is not installed. Ask the user to run the install script first.
APK directory and output directory are specified by the user, or resolved from workspace defaults (see Step 1).
Shortcut-anything โ APK DeepLink Extractor
Tool Reference
| Task | Command |
|---|
| Check / install environment | python3 "$SKILL_DIR/tools/setup.py" --check / --install |
| Unpack APK/XAPK | python3 "$SKILL_DIR/tools/apk_unpacker.py" |
| Parse AndroidManifest | python3 "$SKILL_DIR/tools/manifest_parser.py" |
| Parse Shortcut XML | python3 "$SKILL_DIR/tools/shortcut_parser.py" |
| Scan smali for dynamic registrations | python3 "$SKILL_DIR/tools/smali_scanner.py" |
| Parse Navigation Graph | python3 "$SKILL_DIR/tools/nav_parser.py" |
| Scan RN/Flutter assets | python3 "$SKILL_DIR/tools/assets_scanner.py" |
| Scan exported Activity extras | python3 "$SKILL_DIR/tools/activity_api_scanner.py" |
| ADB validation | python3 "$SKILL_DIR/tools/deeplink_validator.py" |
| One-shot batch processing | python3 "$SKILL_DIR/tools/result_writer.py" |
| Read result JSON | Read tool |
| Write report | Write / Edit tool |
Main Workflow
Step 0: Environment Check
python3 "$SKILL_DIR/tools/setup.py" --check
If anything is missing, ask the user whether to auto-install (Java must be installed manually โ inform the user):
python3 "$SKILL_DIR/tools/setup.py" --install
Step 1: Confirm Target APK
Read "$SKILL_DIR/prompts/intake.md" and follow its instructions to confirm:
- Target APK file(s) (single or batch)
- APK directory and output directory (ask if not specified, or use a sensible default)
- Whether to enable ADB live-device validation
Batch mode (user says "all" or doesn't specify a file):
python3 "$SKILL_DIR/tools/result_writer.py" \
--apk-dir "{apk_dir}" \
--output-dir "{output_dir}"
Single-file mode (user specifies a particular APK):
python3 "$SKILL_DIR/tools/result_writer.py" \
--input "{apk_path}" \
--output-dir "{output_dir}"
No device / user skips validation: append --no-validate
Device connected but no actual launch: append --no-launch
Step 1.5: ADB Validation with Model-Assisted Repair
After result_writer.py finishes, read {output_dir}/{slug}/result.json and run each adb_command via Bash. Apply the same validation + repair loop to both deeplinks and activity_apis.
If the command succeeds (Starting: Intent in output, no error) โ mark validated: true, move on.
If the command fails โ trigger the model repair loop:
- Collect the failed command, the full error output, and the entry's metadata (source, uri/component, extras).
- Reason about why it failed. Common causes:
-n pkg/pkg โ component equals the package name, not an Activity class โ remove -n and rely on scheme routing
- Bare package name appended after
-d uri โ treated as intent spec โ remove it
- URI not registered by the app โ mark invalid, no retry
- Wrong extras format (
-e for binary data instead of --eu) โ fix the flag
- Activity requires a specific extra to not crash โ try launching without extras first, then add one extra at a time
- Construct a corrected command and run it once more.
- If retry succeeds โ mark
validated: true, record "validation_strategy": "model-repaired".
- If retry also fails โ mark
validated: false, "validation_status": "invalid", record both commands and both errors. Do not retry again.
For activity_apis specifically:
- First try
adb_command_no_extras (launch without any extras) โ if the Activity opens without crashing, it works as a plain launcher
- Then try
adb_command (with all extracted extras) โ note whether extras change the destination page
- Update both
validated and validation_note with what was observed
For share_api and search_api entries, use the adb_example field. Note that PROCESS_TEXT cannot be triggered via am start โ skip it and annotate accordingly.
After all commands are tested, update result.json with final validated / validation_status / validation_note values using the Write tool.
Step 2: Smali Candidate Semantic Review
After result_writer.py finishes, smali candidates are written to {output_dir}/{slug}/raw/smali_scan.json under the candidates field, all with confidence: pending_model_review. Before ADB validation, evaluate each candidate semantically:
Criteria (in priority order):
is_priority_file: true โ from a routing/deeplink-related file; high confidence, keep
match_type: register_pattern โ matches a registration call (addURI/registerScheme, etc.); strong signal, keep
context surrounding lines โ check ยฑ3 lines:
- Contains
route, register, dispatch, navigate โ keep
- Contains
log, debug, test, mock, assert, throw โ discard
- String is partial (scheme-only or path-only) โ mark
needs_concat, keep with low confidence
- URI structure โ scheme-only (no host/path) โ low confidence; has host or path โ high confidence
Confidence output:
high โ confirmed valid deeplink, merge into final results
medium โ possibly valid, merge into final results with source annotation
low โ keep, listed separately as "needs review" in report
noise โ discard
Write passing candidates (high/medium/low) to {output_dir}/{slug}/raw/smali_reviewed.json using the Write tool:
{
"deeplinks": [
{
"source": "smali",
"uri": "example://page?param=value",
"scheme": "example",
"host": "page",
"path": null,
"component": null,
"confidence": "high",
"validated": false,
"adb_command": "adb shell am start -a android.intent.action.VIEW -d \"example://page?param=value\" com.example.app",
"evidence": {
"file": "smali/...",
"line": 42,
"raw": "const-string v0, \"example://page?param=value\"",
"is_priority_file": true,
"match_type": "uri_literal",
"note": "URI literal in smali: RouterTable.smali"
}
}
]
}
Once written, result_writer.py will automatically detect and consume this file, merging the smali results into the final result.json.
Step 3: Semantic Analysis
Use the Read tool to load {output_dir}/{slug}/result.json for each app. Follow the analysis dimensions in "$SKILL_DIR/prompts/analyzer.md":
- Add a functional description for each deeplink
- Determine whether query direct-launch is supported
- Flag disabled shortcuts
- Annotate low-confidence smali entries
Step 4: Generate Report
Follow the format in "$SKILL_DIR/prompts/report_builder.md". Show the summary banner first:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ {app_name} โ DeepLink Extraction Complete โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ
โ Package: {package} Version: {version} โ
โ DeepLinks: {total} Shortcuts: {shortcuts} โ
โ Validated: {ok} Share API: {share} โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Then render the full Markdown report (tables + ADB commands).
Step 5: Report Output Locations
Output files:
Single app result : {output_dir}/{slug}/result.json
Raw parsed data : {output_dir}/{slug}/raw/
Batch summary : {output_dir}/all_results.json (batch mode only)
Single-Step Mode (Advanced)
When the user wants to run only one stage:
Unpack only:
python3 "$SKILL_DIR/tools/apk_unpacker.py" \
--input "{apk_path}" \
--output-dir /tmp/sa_decompile/{slug} \
--json
Parse Manifest only:
python3 "$SKILL_DIR/tools/manifest_parser.py" \
--dir /tmp/sa_decompile/{slug} \
--output /tmp/sa_{slug}_manifest.json
Parse Shortcuts only:
python3 "$SKILL_DIR/tools/shortcut_parser.py" \
--dir /tmp/sa_decompile/{slug} \
--package {package} \
--output /tmp/sa_{slug}_shortcuts.json
Scan smali only:
python3 "$SKILL_DIR/tools/smali_scanner.py" \
--dir /tmp/sa_decompile/{slug} \
--package {package} \
--min-confidence medium \
--output /tmp/sa_{slug}_smali.json
Validate only (from an existing deeplink JSON):
python3 "$SKILL_DIR/tools/deeplink_validator.py" \
--input /tmp/sa_{slug}_deeplinks.json \
--package {package} \
--output /tmp/sa_{slug}_validated.json
Error Handling
| Error | Action |
|---|
| apktool fails (corrupted resources) | Retry with --force-manifest |
| XAPK extraction fails | Ask user to unzip manually and locate base.apk |
| ADB device not found | Auto-switch to --no-validate, output pending commands |
| smali scan timeout | Reduce --smali-max-files to 1000 and retry |
| Java not installed | Halt and provide installation instructions |
Management Commands
List extracted apps:
ls "{output_dir}/"
View full result for an app: use the Read tool on {output_dir}/{slug}/result.json
Clear decompile cache (keeps result.json):
rm -rf "{output_dir}/{slug}/decompiled"