agentsclimarketplace

App perf diagnosis skill

Skill AlexBobdylan/app-perf-diagnosis-skill

行動 App 效能異常診斷(手機發熱/卡頓/耗電),全自動化流程:自動編譯 Profile、擷取 VM Service / 原生效能 API、收集 CPU Profiler 資料並靜態掃描效能反模式,支援 Flutter、React Native 等框架。From its SKILL.md

Install
npx -y skills add AlexBobdylan/app-perf-diagnosis-skill

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

11.4 KB, ~4.5k tokens by cl100k_base, as published. Nobody here has run it

行動 App 效能異常診斷 Skill (v2.0)

當使用者提到以下關鍵字時自動觸發:

  • App 發熱、手機燙、過熱
  • 電池耗電快、掉電
  • 畫面卡頓、Jank、掉幀
  • CPU 使用率高
  • WebView 效能問題
  • 效能分析、Profile 模式、效能診斷
  • 記憶體洩漏、Memory leak

階段 1:問題確認與環境準備

請主動向使用者確認:

  1. 症狀描述:發熱?卡頓?耗電?閃退?
  2. 問題畫面:哪個 Screen 或功能?
  3. 是否含 WebView:該畫面是否使用 WebView 載入網頁?
  4. 開發環境:Android Studio / VS Code?

確認後進入下一階段。


階段 2:自動清理並啟動 Profile 模式

2.1 自動殺掉舊的 flutter run 進程

在啟動新的 Profile 前,主動使用 run_command 先清理可能殘留的舊進程,避免 port 衝突:

Windows (PowerShell):

# 偵測並終止殘留的 flutter/dart 進程
$flutterProcs = Get-Process -Name "flutter*","dart*" -ErrorAction SilentlyContinue
if ($flutterProcs) {
    Write-Host "⚠️ 偵測到 $($flutterProcs.Count) 個殘留進程,正在清理..."
    $flutterProcs | Stop-Process -Force
    Start-Sleep -Seconds 2
    Write-Host "✅ 清理完成"
} else {
    Write-Host "✅ 無殘留進程"
}

2.2 啟動 Profile 模式

主動使用 run_command 依序執行:

flutter clean
flutter pub get
flutter run --profile

在呼叫指令前,請先告知使用者即將執行的動作,以取得介面上的核准。


階段 3:擷取 VM Service 並收集 CPU 效能資料

3.1 取得 VM Service URL

成功啟動後,從終端機輸出中找到: A Dart VM Service on [Device] is available at: http://127.0.0.1:xxxxx/yyyyyyyyy=/

向使用者提示切換到問題畫面並操作。

3.2 全自動 CPU 資料收集(具體 PowerShell 指令)

當使用者回覆準備好後,主動使用 run_command 執行以下指令。 將 $vmServiceUrl 替換為實際取得的 URL:

# ===== 步驟 A:取得 Isolate ID =====
$vmServiceUrl = "http://127.0.0.1:62895/jrpVApZ7cTM=/"  # ← 替換為實際 URL
$vmResponse = Invoke-RestMethod -Uri "${vmServiceUrl}getVM" -Method Get
$mainIsolateId = ($vmResponse.result.isolates | Where-Object { $_.name -eq "main" }).id
Write-Host "✅ Main Isolate ID: $mainIsolateId"

# ===== 步驟 B:收集 CPU Samples(最近 15 秒)=====
$now = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
$startTime = $now - 15000  # 往回抓 15 秒
$cpuUrl = "${vmServiceUrl}getCpuSamples?isolateId=$mainIsolateId&timeOriginMicros=$($startTime * 1000)&timeExtentMicros=15000000"
$cpuData = Invoke-RestMethod -Uri $cpuUrl -Method Get

# ===== 步驟 C:解析 Top 10 熱點函式 =====
$functions = @{}
foreach ($sample in $cpuData.result.samples) {
    $stackFrames = $sample.stack
    if ($stackFrames.Count -gt 0) {
        $topFrame = $stackFrames[0]
        $funcName = $cpuData.result.functions[$topFrame].function.name
        if ($functions.ContainsKey($funcName)) {
            $functions[$funcName]++
        } else {
            $functions[$funcName] = 1
        }
    }
}
$totalSamples = $cpuData.result.samples.Count
Write-Host "`n📊 CPU 熱點 Top 10(共 $totalSamples 個 Samples):"
$functions.GetEnumerator() | Sort-Object Value -Descending | Select-Object -First 10 | ForEach-Object {
    $pct = [math]::Round(($_.Value / $totalSamples) * 100, 1)
    Write-Host "  $($_.Key): $($_.Value) samples ($pct%)"
}

備用方案:若 VM Service API 無法直接呼叫(如防火牆阻擋),請向使用者索取 DevTools 網頁的 CPU Profiler → Bottom Up 截圖來做視覺分析。


階段 4:Log 關鍵字自動判讀

在 Profile 運行期間,主動監控終端機輸出,比對以下規則表自動判讀嚴重等級:

🔴 致命級(Critical)— 需立即處理

Log 關鍵字判定問題建議動作
Skipped N frames!(N > 100)主執行緒被嚴重阻塞檢查 CPU Profiler Top 函式
OutOfMemoryError記憶體溢出→ 進入階段 6(記憶體分析)
ANRApplication Not Responding應用無回應檢查主執行緒是否有同步 I/O

🟡 警告級(Warning)— 需關注

Log 關鍵字判定問題建議動作
Skipped N frames!(30 < N ≤ 100)中度幀延遲檢查 build() 方法複雜度
MutationObserver 反覆出現WebView DOM 監聽堆疊→ 進入階段 5 反模式掃描
setState() called after dispose()生命週期管理錯誤加入 if (!mounted) return;
metadata version X.X.0, expected Y.Y.0Kotlin 版本衝突鎖定 resolutionStrategy

🟢 資訊級(Info)— 可忽略

Log 關鍵字判定問題
Skipped N frames!(N ≤ 30)輕微卡頓,通常可接受
Reloaded X of Y libraries正常 Hot Reload

階段 5:全自動原始碼掃描(擴大版反模式清單)

主動使用 grep_search 對問題畫面原始碼及相關檔案進行掃描。

5.1 🔴 WebView 致命反模式

搜尋關鍵字反模式說明嚴重度
runJavaScript + querySelectorAll('*')DOM 全遍歷,每次觸發序列化上千個元素🔴 致命
Timer.periodic + runJavaScript定時器不斷注入 JS,CPU 持續高負載🔴 致命
setInterval 在注入的 JS 中JS 層的定時器與 Dart 定時器疊加🔴 致命
new MutationObserver 重複注入每次注入都新增一個 Observer🔴 致命

標準修復模板

/// ✅ 輕量版 CSS 注入(只注入一次,用 ID 防重複)
void _injectStyleOnce() {
    _controller.runJavaScript('''
        if (!document.getElementById('app-fix-style')) {
            var style = document.createElement('style');
            style.id = 'app-fix-style';
            style.textContent = `* { font-size: 12px !important; }`;
            document.head.appendChild(style);
        }
    ''');
}

5.2 🟡 Widget 重建過度

搜尋關鍵字反模式說明嚴重度
setStateTimer.periodic 回呼中高頻整頁重建🟡 警告
setStateStreamBuilderlisten應使用 StreamBuilder 而非手動 setState🟡 警告
整個 build() 方法超過 200 行單一 Widget 過度龐大🟡 警告

5.3 🟡 資源未釋放(記憶體洩漏源)

搜尋關鍵字反模式說明嚴重度
StreamSubscription 無對應 .cancel()Stream 訂閱未關閉🟡 警告
AnimationController 無對應 .dispose()動畫控制器未釋放🟡 警告
Timer.periodic 無對應 .cancel()定時器未在 dispose() 中清除🟡 警告
ScrollController 無對應 .dispose()捲軸控制器未釋放🟡 警告
TextEditingController 無對應 .dispose()文字輸入控制器未釋放🟡 警告
FocusNode 無對應 .dispose()焦點節點未釋放🟡 警告

5.4 🟡 圖片與資源效能

搜尋關鍵字反模式說明嚴重度
Image.networkcacheWidth / cacheHeight大圖未降解析度,佔用大量記憶體🟡 警告
Image.asset 載入超過 2MB 的圖片資源圖片過大🟡 警告
BoxDecoration + DecorationImage 無 resize背景圖未最佳化🟢 建議

階段 6:記憶體分析(Memory Profiling)

如果 CPU 分析未發現明顯問題,或症狀包含「越用越卡」「長時間使用後閃退」,則進入記憶體分析。

6.1 使用 VM Service API 取得記憶體分配

主動使用 run_command 執行:

# ===== 取得記憶體分配概況 =====
$vmServiceUrl = "http://127.0.0.1:62895/jrpVApZ7cTM=/"  # ← 替換為實際 URL
$mainIsolateId = "isolates/XXXXXXXXXX"  # ← 使用階段 3 取得的 ID

$allocUrl = "${vmServiceUrl}getAllocationProfile?isolateId=$mainIsolateId&gc=true"
$allocData = Invoke-RestMethod -Uri $allocUrl -Method Get

# 解析記憶體摘要
$heapUsed = [math]::Round($allocData.result.memoryUsage.heapUsage / 1MB, 2)
$heapCap = [math]::Round($allocData.result.memoryUsage.heapCapacity / 1MB, 2)
$extUsed = [math]::Round($allocData.result.memoryUsage.externalUsage / 1MB, 2)

Write-Host "`n🧠 記憶體概況:"
Write-Host "  Heap 使用: ${heapUsed} MB / ${heapCap} MB"
Write-Host "  External:  ${extUsed} MB"
Write-Host "  使用率:    $([math]::Round(($heapUsed / $heapCap) * 100, 1))%"

6.2 記憶體判讀規則

指標正常需關注危險
Heap 使用率< 60%60-85%> 85%
External Memory< 50 MB50-150 MB> 150 MB
持續增長趨勢穩定平坦緩慢上升持續攀升不回落

階段 7:產出標準化診斷報告

結合所有分析結果,主動產出 Artifact 報告(檔名:perf_diagnosis_report.md)。

📋 報告固定範本:

# 📋 效能診斷報告

**診斷日期:** YYYY-MM-DD
**診斷人員:** [開發者姓名]
**目標畫面:** [畫面名稱 / Screen 檔案路徑]
**診斷工具:** Flutter DevTools (CPU Profiler + Memory)
**App 版本:** [版本號]

---

## 一、問題摘要

| 項目 | 內容 |
|------|------|
| 使用者回報症狀 | [發熱 / 卡頓 / 耗電 / 閃退] |
| 根因判定 | [一句話描述根本原因] |
| 嚴重等級 | [🔴 致命 / 🟡 警告 / 🟢 輕微] |

---

## 二、CPU 分析數據

### Top 5 熱點函式

| 排名 | 函式名稱 | Self Time | 佔比 | 歸因 |
|------|---------|-----------|------|------|
| 1 | [函式名] | [時間] | [XX%] | [WebView通訊/Widget重建/佈局計算] |
| 2 | ... | ... | ... | ... |

### 判讀結論
[根據 CPU 數據的結論性分析]

---

## 三、記憶體分析數據(如適用)

| 指標 | 數值 | 狀態 |
|------|------|------|
| Heap 使用 | XX MB / XX MB | [正常/警告/危險] |
| External | XX MB | [正常/警告/危險] |
| 趨勢 | [穩定/上升/持續攀升] | — |

---

## 四、原始碼問題定位

### 問題 1:[問題標題]
- **檔案:** `[檔案路徑]`
- **行號:** L[XX] - L[XX]
- **嚴重度:** [🔴/🟡/🟢]
- **問題程式碼:**
```dart
// ❌ 問題程式碼
  • 修復建議:
// ✅ 修復後程式碼

五、修復前後對比

指標修復前修復後改善幅度
WebView CPU 佔比XX%XX%↓XX%
FPSXX fpsXX fps↑XX fps
體感溫度異常發熱正常

六、後續建議

  • [建議事項 1]
  • [建議事項 2]
  • [建議事項 3]

---

## 附錄:Kotlin 版本衝突速查

若編譯階段遇到 `metadata version` 錯誤,在 `android/build.gradle` 的 `allprojects` 加入:
```gradle
configurations.all {
    resolutionStrategy {
        force "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
        force "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
        force "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    }
}

What ships with it: 2 files

6.2 KB alongside SKILL.md

Keep looking

Skills are one crate of 326,149. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.