Skip to content

feat: Add ExternalControlReceiver for silent background automation#644

Closed
whjstc wants to merge 3 commits intoMetaCubeX:mainfrom
whjstc:feature/broadcast-receiver-automation
Closed

feat: Add ExternalControlReceiver for silent background automation#644
whjstc wants to merge 3 commits intoMetaCubeX:mainfrom
whjstc:feature/broadcast-receiver-automation

Conversation

@whjstc
Copy link
Copy Markdown

@whjstc whjstc commented Dec 11, 2025

Problem

ExternalControlActivity causes screen flash/popup on some ROMs (Flyme, MIUI, ColorOS) when triggered by automation tools like Tasker, breaking the silent background control experience.

Solution

Adds ExternalControlReceiver — a BroadcastReceiver that handles START/STOP/TOGGLE actions completely in the background, with no UI triggered.

This complements the App Shortcuts approach added in #676 (which targets Samsung Routines and launcher long-press). The BroadcastReceiver approach targets Tasker and other tools that send explicit broadcast intents.

Root cause fix (previously unreliable STOP)

The initial version of this PR checked Remote.broadcasts.clashRunning to decide whether to call stopClashService(). This is an in-memory value that gets reset to false in Broadcasts.unregister() whenever the app goes to the background — so the condition always evaluated to false when Tasker triggered the receiver, and stopClashService() was never called.

Fix: replaced with StatusClient(context).currentProfile() != null, which queries the StatusProvider ContentProvider directly via IPC. This is real-time and independent of whether the app is in the foreground — the same method Broadcasts.register() uses to initialize state.

No KeepAliveService or persistent notification required.

Usage (Tasker)

Action: Send Intent

  • Action: com.github.metacubex.clash.meta.action.STOP_CLASH (or START / TOGGLE)
  • Target: Broadcast Receiver
  • Package: com.github.metacubex.clash.meta
  • Class: (leave empty)

Files changed

  • app/src/main/java/.../ExternalControlReceiver.kt — BroadcastReceiver implementation
  • app/src/main/AndroidManifest.xml — register receiver
  • TASKER_GUIDE.md — user guide with examples

个人使用的文档和工具:
- BUILD_GUIDE.md - 构建指南
- SUCCESS.md - 构建成功说明
- SETUP_COMPLETE.md - 环境配置记录
- BROADCAST_RECEIVER_WORKING.md - 测试记录
- CLAUDE.md - 项目说明
- PR_GUIDE.md - PR 提交指南
- build.sh, check-env.sh, prepare-pr.sh - 构建脚本
- build.gradle.kts - 支持自定义 keystore 路径

这些文件不会影响上游 PR。
@whjstc whjstc changed the title feat: Add BroadcastReceiver for background automation control feat: Add BroadcastReceiver with KeepAliveService for reliable automation Dec 16, 2025
@swwrww
Copy link
Copy Markdown

swwrww commented Jan 5, 2026

我的破澎湃
用Target: Broadcast Receiver无效
用Target: Activity可行

@whjstc
Copy link
Copy Markdown
Author

whjstc commented Jan 6, 2026

我的破澎湃 用Target: Broadcast Receiver无效 用Target: Activity可行

用的是是我这边编译的 apk,还是 MetaCubeX 原仓库发布的版本?

@swwrww
Copy link
Copy Markdown

swwrww commented Jan 8, 2026

我的破澎湃 用Target: Broadcast Receiver无效 用Target: Activity可行

用的是是我这边编译的 apk,还是 MetaCubeX 原仓库发布的版本?

可以了,太棒了!无感开关。谢谢大佬!

@whjstc
Copy link
Copy Markdown
Author

whjstc commented Jan 8, 2026

我的破澎湃 用Target: Broadcast Receiver无效 用Target: Activity可行

用的是是我这边编译的 apk,还是 MetaCubeX 原仓库发布的版本?

可以了,太棒了!无感开关。谢谢大佬!

最近我也发现,后台运行久了,会有自动关不掉的情况,先这样将就了,以后有时间再研究。

whjstc and others added 2 commits April 5, 2026 00:34
Merge upstream MetaCubeX/ClashMetaForAndroid up to v2.11.25:
- Add dynamic App Shortcuts for Tasker/Samsung Routines (MetaCubeX#676)
- Mark MainActivity as singleTask (MetaCubeX#665)
- Support hiding app from Recents screen (MetaCubeX#663)
- Adapt hidden field for proxy groups (MetaCubeX#685)
- Fix seccomp on 32-bit Android <= 10
- Update dependencies and toolchain
Adds a BroadcastReceiver allowing Tasker and other automation tools to
control Clash (START/STOP/TOGGLE) without triggering any UI or screen
activity, complementing the existing App Shortcuts approach (MetaCubeX#676).

Root cause of previous unreliability: the initial implementation checked
Remote.broadcasts.clashRunning (in-memory state reset to false when app
goes background), so the stop condition always failed in background.
Fixed by querying StatusClient.currentProfile() != null for real-time
state via ContentProvider IPC, independent of app foreground status.

No persistent notification or foreground service required.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@whjstc whjstc force-pushed the feature/broadcast-receiver-automation branch from 0a227a2 to 18eb3d6 Compare April 4, 2026 16:43
@whjstc whjstc changed the title feat: Add BroadcastReceiver with KeepAliveService for reliable automation feat: Add ExternalControlReceiver for silent background automation Apr 4, 2026
@whjstc
Copy link
Copy Markdown
Author

whjstc commented Apr 4, 2026

Update: Found and fixed the root cause of the unreliable STOP issue I mentioned earlier.

The problem was that ExternalControlReceiver checked Remote.broadcasts.clashRunning before calling stopClashService(). This is an in-memory value — it gets reset to false in Broadcasts.unregister() when the app goes to the background, so the condition was always false when Tasker triggered the receiver. stopClashService() was never actually called.

Fix: replaced with StatusClient(context).currentProfile() != null, which queries the StatusProvider ContentProvider directly. No foreground service or persistent notification needed — removed KeepAliveService entirely.

Also rebased onto current main (v2.11.25), so the diff is now clean — only 3 files: ExternalControlReceiver.kt, AndroidManifest.xml, and TASKER_GUIDE.md.

@whjstc whjstc closed this Apr 4, 2026
@whjstc whjstc deleted the feature/broadcast-receiver-automation branch April 4, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants