最近收到一个需求,需要监控用户的按键行为来启动应用。类似与快捷键启动应用的方式。

方案

使用AccessibilityService来监听用户行为。

AccessibilityService是什么

Google为了让Android系统更实用,为用户提供了无障碍辅助服务(AccessibilityService).

AccessibilityService运行在后台,并且能够收到由系统发出的一些事件(AccessibilityEvent,这些事件表示用户界面一系列的状态变化),比如焦点改变,输入内容变化,按钮被点击了等等,该种服务能够请求获取当前活动窗口并查找其中的内容.换言之,界面中产生的任何变化都会产生一个时间,并由系统通知给AccessibilityService.这就像监视器监视着界面的一举一动,一旦界面发生变化,立刻发出警报.

更多详情,请阅读官方文档:官方文档。或查阅其他相关资料。

实例

MyKeyService.java

public class MyKeyService extends AccessibilityService {
    private AccessibilityServiceInfo mAccessibilityServiceInfo;
    protected static final String TAG = "tangtangAccessibilityService";

    @SuppressLint("LongLogTag")
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: MyKeyService isStart !");
    }

    @SuppressLint("LongLogTag")
    @Override
    protected boolean onKeyEvent(KeyEvent paramKeyEvent) {
        Log.d(TAG, "onKeyEvent " + paramKeyEvent);
        return false;//如果返回true,就会导致其他应用接收不到事件了,但是对KeyEvent的修改是不会分发到其他应用中的!
    }

    @SuppressLint("LongLogTag")
    @Override
    public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
        System.out.println("KEYCODE_onAccessibilityEvent");
        Log.i(TAG, "KEYCODE_onAccessibilityEvent");
    }

    @Override
    public void onInterrupt() {

    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.showimage.start.myapplication"
    android:sharedUserId="android.uid.system">
    <!---android:sharedUserId="android.uid.system" 系统权限-->


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!---监听服务-->
        <service
            android:name=".AccessibilityService.MyKeyService"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibilityservice" />
        </service>
    </application>

</manifest>

accessibilityservice.xml

在工程res目录下创建xml目录,同时在xml目录下创建accessibilityservice.xml文件

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
        android:accessibilityEventTypes="typeAllMask"
        android:accessibilityFeedbackType="feedbackGeneric"
        android:accessibilityFlags="flagRequestFilterKeyEvents"
        android:canRetrieveWindowContent="true"
        android:canRequestFilterKeyEvents="true"
        android:description="@string/app_name">
</accessibility-service>

无障碍辅助功能开启方式

简介

开启方式将就是enabled_accessibility_services和accessibility_enabled值写入到settings的secure相关文件中去。

//android 5.1以下平台

/data/user/0/com.android.settings/databases/search_index.db

//android 6.0以上平台

/data/system/users/0/

//无障碍辅助功能相关值
INSERT INTO "secure" VALUES(86,'enabled_accessibility_services','com.showimage.start.myapplication/com.showimage.start.myapplication.AccessibilityService.MyKeyService');
INSERT INTO "secure" VALUES(87,'accessibility_enabled','1');

手动开启

设置--->无障碍--->你的服务--->打开。

android service监听音量上下键 android service监听按键_android

android service监听音量上下键 android service监听按键_无障碍_02

android service监听音量上下键 android service监听按键_android_03

android service监听音量上下键 android service监听按键_xml_04

跳转到无障碍服务设置页

程序员的打开方式。

Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

代码开启

需要注意的是这个需要系统权限

//关闭无障碍服务
    private void autoCloseAccessibilityService(Context context){
        if (isStartAccessibilityServiceEnable(context)) {
            String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
            ComponentName selfComponentName = new ComponentName(context.getPackageName(), KeyInterceptService.class.getCanonicalName());
            String flattenToString = selfComponentName.flattenToString();
            enabledServicesSetting=enabledServicesSetting.replace(":"+flattenToString , "");

            Settings.Secure.putString(context.getContentResolver(),Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,enabledServicesSetting);
            //Settings.Secure.putInt(context.getContentResolver(),Settings.Secure.ACCESSIBILITY_ENABLED, 0);
            Log.d(TAG, "autoCloseAccessibilityService: SETTING ACCESSIBILITY SUCCESS!");
        }
        return;
    }

    //开启无障碍服务
    private void autoOpenAccessibilityService(Context context){
        if (!isStartAccessibilityServiceEnable(context)) {
            String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
            ComponentName selfComponentName = new ComponentName(context.getPackageName(), KeyInterceptService.class.getCanonicalName());
            String flattenToString = selfComponentName.flattenToString();
            if (enabledServicesSetting==null||
                    !enabledServicesSetting.contains(flattenToString)) {
                enabledServicesSetting += ":"+flattenToString;
            }
            Settings.Secure.putString(context.getContentResolver(),Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,enabledServicesSetting);
            Settings.Secure.putInt(context.getContentResolver(),Settings.Secure.ACCESSIBILITY_ENABLED, 1);
            Log.d(TAG, "autoOpenAccessibilityService: SETTING ACCESSIBILITY SUCCESS!");
        }
        return;
    }

    /**
     * 判断无障碍服务是否开启
     *
     * @param context
     * @return
     */
    private boolean isStartAccessibilityServiceEnable(Context context) {
        AccessibilityManager accessibilityManager = (AccessibilityManager)context.getSystemService(Context.ACCESSIBILITY_SERVICE);
        assert accessibilityManager != null;
        List<AccessibilityServiceInfo> accessibilityServices = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
        for (AccessibilityServiceInfo info : accessibilityServices) {
            if (info.getId().contains(context.getPackageName())) {
                return true;
            }
        }
        return false;
    }

命令开启

也需要系统权限。

settings put secure enabled_accessibility_services com.showimage.start.myapplication/com.showimage.start.myapplication.AccessibilityService.MyKeyService
settings put secure accessibility_enabled 1

结束语

以上就是本次分享的辅助服务监听系统按键(AccessibilityService)相关知识以及实例。