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 的類型。常見的類型包括:
四、我們的修復嘗試過程
第一步:建立 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> 中無法同時聲明這兩種類型。
六、我們嘗試的解決方案
方案一:建立獨立的 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 上暫時無法使用
原因:
- Android 的
foregroundServiceType是靜態宣告的 DATASYNC和MEDIAPROJECTION無法在同一個<service>中宣告- 當嘗試用不匹配的類型建立 MediaProjection 時,系統會拒絕
為什麼官方沒有這個問題?
這可能是因為:
- 官方版本使用了不同的架構設計
- 可能有其他我們沒有找到的補丁
- 可能在特定的 Android 版本上可以運作
八、給未來開發者的建議
如果你想要繼續研究這個問題,以下是我們的建議:
1. 研究官方的実装
建議查看 OpenClaw 官方 GitHub 的最新原始碼,看看他們是否有解決方案。
2. 嘗試不同的 Android 版本
我們只測試了 Android 16 (Vivo V2514),也許在其他 Android 版本上有不同的行為。
3. 考慮使用替代方案
如果真的需要螢幕錄製功能,可以考慮:
- 使用手機內建的螢幕錄製功能
- 使用 ADB 指令進行錄製
- 使用第三方螢幕錄製 App 並透過 OpenClaw 呼叫
4. 關鍵原始碼位置
如果你想繼續研究,以下是重要的檔案位置:
九、目前穩定的版本
經過我們的修改,以下是目前穩定可用的版本:
- 版本號: 2026.4.19.09ver
- 包含功能: Camera、Calendar、Device、Location、Photos
- 不包含: screen.record(暫時無法使用)
十、修改過的檔案清單
以下是這次研究中修改過(或新增)的檔案:
新增的檔案
ActivityTracker.kt- Activity 追蹤機制
修改的檔案
MainActivity.kt- 註冊 ScreenRecordActivityResultHolderScreenRecordActivityResultHolder.kt- 新增 callback 機制NodeRuntime.kt- 使用 ActivityTrackerNodeApp.kt- 註冊 ActivityTracker
回滾的修改
NodeForegroundService.kt- 維持dataSync類型AndroidManifest.xml- 維持dataSync類型
十一、結語
雖然這次研究沒有成功解決 screen.record 的問題,但我們學到了很多:
- 了解了 Android Foreground Service 的運作方式
- 學會了如何使用 ActivityLifecycleCallbacks 追蹤 Activity
- 理解了 ActivityResult API 的使用方式
- 體驗了 Android 權限系統的嚴格性
希望這篇文章能幫助到未來想要研究這個問題的人!
如果你成功解決了這個問題,歡迎分享你的做法!
文章更新:2026-04-19
感謝微風提供測試設備和耐心陪我研究!
留言
張貼留言
歡迎留下您的心靈足跡👍