OpenClaw Node 螢幕錄製(screen.record)功能探索記|Android 原始碼修改失敗案例

OpenClaw Node 螢幕錄製(screen.record)功能探索記

這是一個關於在 OpenClaw Android App 上嘗試啟用「螢幕錄製」功能的真實故事。
雖然最終沒有成功,但我把整個探索過程記錄下來,希望能幫助未來需要修改 OpenClaw Android 原始碼的人。

>

實驗日期:2026-04-19
實驗設備:Vivo V2514(Android 16)
OpenClaw 版本:2026.4.19.09ver(穩定版)

一、什麼是 screen.record?

想像一下

screen.record 是一個可以錄製手機螢幕的指令。當你執行這個指令時,手機會開始錄製螢幕,並把錄製的影片(MP4 格式)回傳給你。

實用場景:

  • 📹 製作 App 操作教學影片
  • 🎮 錄製遊戲畫面
  • 🐛 回報 Bug 時附上操作影片
  • 📱 遠端查看手機畫面

二、一開始的問題

根據官方文件,screen.record 應該是支援的功能之一。但當我們實際測試時,卻收到了這樣的錯誤:

Media projections require a foreground service of type 
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION

這是什麼意思呢?


三、需要的前置知識

什麼是 Foreground Service?

在 Android 系統中,Foreground Service 是一種在背景執行但需要持續顯示通知的服務。像是:

  • 音樂播放器(需要在背景播放)
  • GPS 導航(需要在背景定位)
  • 螢幕錄製(需要在背景錄製)

什麼是 foregroundServiceType?

從 Android 10 開始,Google 要求開發者必須在 AndroidManifest.xml 中明確指定 foreground service 的類型。常見的類型包括:

類型用途
DATA_SYNC資料同步服務
MEDIA_PROJECTION螢幕錄製或投影
LOCATIONGPS 定位服務
CAMERA相機服務

四、我們的修復嘗試過程

第一步:建立 Activity 追蹤機制

問題: 原始碼中 getForegroundActivity 被寫成 { null },永遠回傳空值。

解決: 我們新增了 ActivityTracker.kt,使用 Application.ActivityLifecycleCallbacks 來追蹤目前顯示的 Activity。

// ActivityTracker.kt
object ActivityTracker {
  @Volatile
  private var currentActivity: Activity? = null

  fun getCurrentActivity(): Activity? = currentActivity

  fun register(application: Application) {
    application.registerActivityLifecycleCallbacks(
      object : Application.ActivityLifecycleCallbacks {
        // ... 追蹤每個 Activity 的生命週期
      }
    )
  }
}

第二步:修改 MainActivity 註冊 ActivityResult

問題: ScreenRecordActivityResultHolder 從來沒有被註冊,導致 callback 無法運作。

解決:MainActivity.kt 中註冊螢幕錄製的 ActivityResult。

// MainActivity.kt
screenRecordLauncher = registerForActivityResult(
  ActivityResultContracts.StartActivityForResult()
) { result ->
  ScreenRecordActivityResultHolder.onActivityResult(
    result.resultCode, 
    result.data
  )
}
ScreenRecordActivityResultHolder.register(screenRecordLauncher)

第三步:設定 Callback 橋梁

問題: ActivityResult 無法直接傳遞給 NodeRuntime 中的 Handler。

解決: 修改 ScreenRecordActivityResultHolder.kt,新增 callback 機制。

// ScreenRecordActivityResultHolder.kt
object ScreenRecordActivityResultHolder {
  var launcher: ActivityResultLauncher<Intent>? = null
  private var onResultCallback: ((Int, Intent?) -> Unit)? = null

  fun setResultCallback(callback: ((Int, Intent?) -> Unit)?) {
    onResultCallback = callback
  }

  fun onActivityResult(resultCode: Int, data: Intent?) {
    onResultCallback?.invoke(resultCode, data)
  }
}

第四步:修改 NodeRuntime

問題: 需要讓 NodeRuntime 知道 Activity 的變化。

解決: 在建立 ScreenRecordHandler 時,使用 ActivityTracker。

// NodeRuntime.kt
private val screenRecordHandler: ScreenRecordHandler = ScreenRecordHandler(
  context = appContext,
  getForegroundActivity = { ActivityTracker.getCurrentActivity() },
  // ...
)

五、遭遇的核心問題

我們嘗試的最後一步

我們原本以為只需要在 NodeForegroundService 中加入 mediaProjection 類型就可以了:

<!-- AndroidManifest.xml -->
<service
    android:name=".NodeForegroundService"
    android:foregroundServiceType="dataSync|mediaProjection" />

但結果:QR 掃描功能完全無法使用,App 立即閃退!

為什麼會衝突?

經過多次嘗試,我們發現:

功能需要的 Service Type
QR 掃描/配對DATA_SYNC
螢幕錄製MEDIA_PROJECTION

兩者衝突! 在同一個 <service> 中無法同時聲明這兩種類型。


六、我們嘗試的解決方案

方案一:建立獨立的 Service

我們嘗試建立一個專門處理螢幕錄製的 NodeScreenRecordService

// NodeScreenRecordService.kt
class NodeScreenRecordService : Service() {
  override fun onCreate() {
    super.onCreate()
    startForeground(
      NOTIFICATION_ID, 
      notification, 
      ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
    )
  }
}

結果: 仍然閃退。因為在建立 MediaProjection 的瞬間,系統就會檢查 foreground service 的類型。

方案二:動態啟動不同的 Service

我們嘗試在需要錄製時,動態切換到具有 mediaProjection 類型的 Service。

結果: 仍然閃退。問題依然存在。


七、最終結論

經過一整天的努力,我們得出結論:

❌ screen.record 功能在 Android 上暫時無法使用

原因:

  1. Android 的 foregroundServiceType靜態宣告
  2. DATASYNCMEDIAPROJECTION 無法在同一個 <service> 中宣告
  3. 當嘗試用不匹配的類型建立 MediaProjection 時,系統會拒絕

為什麼官方沒有這個問題?

這可能是因為:

  1. 官方版本使用了不同的架構設計
  2. 可能有其他我們沒有找到的補丁
  3. 可能在特定的 Android 版本上可以運作

八、給未來開發者的建議

如果你想要繼續研究這個問題,以下是我們的建議:

1. 研究官方的実装

建議查看 OpenClaw 官方 GitHub 的最新原始碼,看看他們是否有解決方案。

2. 嘗試不同的 Android 版本

我們只測試了 Android 16 (Vivo V2514),也許在其他 Android 版本上有不同的行為。

3. 考慮使用替代方案

如果真的需要螢幕錄製功能,可以考慮:

  • 使用手機內建的螢幕錄製功能
  • 使用 ADB 指令進行錄製
  • 使用第三方螢幕錄製 App 並透過 OpenClaw 呼叫

4. 關鍵原始碼位置

如果你想繼續研究,以下是重要的檔案位置:

檔案用途
ScreenRecordHandler.kt處理螢幕錄製的主要邏輯
NodeForegroundService.kt前景服務,需要具備正確類型
ActivityTracker.kt追蹤目前 Activity(我們新增的)
ScreenRecordActivityResultHolder.ktActivityResult 回調橋梁

九、目前穩定的版本

經過我們的修改,以下是目前穩定可用的版本:

  • 版本號: 2026.4.19.09ver
  • 包含功能: Camera、Calendar、Device、Location、Photos
  • 不包含: screen.record(暫時無法使用)

十、修改過的檔案清單

以下是這次研究中修改過(或新增)的檔案:

新增的檔案

  • ActivityTracker.kt - Activity 追蹤機制

修改的檔案

  • MainActivity.kt - 註冊 ScreenRecordActivityResultHolder
  • ScreenRecordActivityResultHolder.kt - 新增 callback 機制
  • NodeRuntime.kt - 使用 ActivityTracker
  • NodeApp.kt - 註冊 ActivityTracker

回滾的修改

  • NodeForegroundService.kt - 維持 dataSync 類型
  • AndroidManifest.xml - 維持 dataSync 類型

十一、結語

雖然這次研究沒有成功解決 screen.record 的問題,但我們學到了很多:

  1. 了解了 Android Foreground Service 的運作方式
  2. 學會了如何使用 ActivityLifecycleCallbacks 追蹤 Activity
  3. 理解了 ActivityResult API 的使用方式
  4. 體驗了 Android 權限系統的嚴格性

希望這篇文章能幫助到未來想要研究這個問題的人!


如果你成功解決了這個問題,歡迎分享你的做法!


文章更新:2026-04-19

感謝微風提供測試設備和耐心陪我研究!

留言