| 方案 | 可行性 | 限制 |
|---|---|---|
| 懸浮窗 + 普通觸摸事件分發 | ❌ 不可行 | APP 無法向系統注入觸摸事件(需系統簽名權限 INJECT_EVENTS) |
| Root + shell input tap | ⚠️ 受限 | 需 Root、SELinux 限制、安全風險大、Google Play 禁止 |
| AccessibilityService (無障礙服務) | ✅ 官方支援 | 需用戶手動開啟無障礙權限、部分設備 ROM 限制、Google Play 政策審核嚴格 |
| 測試工具 | ✅ 官方支援 | 僅限測試場景,需 USB 偵錯、非正式發布 |
<service android:name=".ClickService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:label="@string/accessibility_name">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="@xml/accessibility_config" />
</service>
<accessibility-service
xmlns:android="https://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
android:packageNames="target.package.name" // 限定目標包,或留空全局
android:accessibilityFeedbackType="feedbackGeneric"
android:canRetrieveWindowContent="true"
android:canPerformGestures="true" // 關鍵:允許模擬手勢
android:notificationTimeout="100" />
public class ClickService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// 監聽目標視窗變化,尋找目標按鈕節點
AccessibilityNodeInfo root = getRootInActiveWindow();
if (root == null) return;
List buttons = root.findAccessibilityNodeInfosByViewId("target_button_id");
if (!buttons.isEmpty()) {
performClick(buttons.get(0));
}
}
private void performClick(AccessibilityNodeInfo node) {
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
// 懸浮窗通知服務點擊座標(跨進程通訊:Broadcast / Messenger / AIDL)
public void clickAt(float x, float y) {
// API 24+ 可用 GestureDescription 模擬精確點擊
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
GestureDescription.StrokeDescription stroke =
new GestureDescription.StrokeDescription(
Path().apply { moveTo(x, y) }, 0, 100);
GestureDescription gd = new GestureDescription.Builder().addStroke(stroke).build();
dispatchGesture(gd, null, null);
}
}
}
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
dispatchGesture 精確座標點擊,舊版僅能 ACTION_CLICK 節點級點擊。若為**自動化測試**,請使用 UIAutomator2 或 Appium,配合 adb 權限授予(adb shell pm grant pkg android.permission.INJECT_EVENTS),無需發布給終端用戶。
**普通 App 無法直接注入點擊事件**。若確有輔助需求,**AccessibilityService 是唯一官方合法路徑**,但必須嚴格遵守「服務於殘障用戶」原則並通過 Play 審核。測試自動化請走 UIAutomator/Appium 體系。