关注IP属地: 上海
0.0742019.12.18 22:48:02字数 657阅读 6,959
在手机更多设置或者高级设置中,有个辅助功能(有些手机也叫无障碍功能),很多人不知道这个功能具体是干嘛的,其实这个功能是为了增强用户界面以帮助残障人士,或者可能暂时无法与设备充分交互的人们。
其原理是通过在后台运行一个AccessibilityService服务,利用AccessibilityEvent接收指定事件的回调,这些事件代表的是用户界面上的一些操作,例如:焦点改变、点击按钮、弹出横幅通知等等。所以这样的服务具有请求活动窗口内容的能力。简单的说AccessibilityService就是一个后台监控服务,当你监控的内容发生改变时,就会调用后台服务的回调方法。使用场景包括自动抢红包、自动安装app、后台服务保活等。
辅助功能在手机中的入口
<service android:name=".SimulatedClickService"
android:enabled="true"
android:exported="true"
android:label="@string/click_window_screen"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<action android:name="android.accessibilityservice.AccessibilityService"/>
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config"/>
</service>
SimulatedClickService:继承自AccessibilityService类
accessibility_service_config:这是一个配置文件,里面存放AccessibilityService的配置信息(见2.2)
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds|flagRetrieveInteractiveWindows"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true"
android:description="@string/click_window_screen"
android:notificationTimeout="100"
tools:ignore="UnusedAttribute"/>
上一小节提到的accessibility_service_config文件配置如上,各参数的含义:
accessibilityEventTypes:响应的事件类型(单击、长按、滑动、通知等),typeAllMask表示响应全部事件
accessibilityFeedbackType:反馈方式,比如是语音播放,还是震动等
accessibilityFlags:需要获取哪些信息,有flagDefault、flagReportViewIds和flagRetrieveInteractiveWindows可以使用,具体代表什么含义可以参考:
canPerformGestures:是否允许app发送手势(api24及以上才可以使用手势)
description:描述(会在开启辅助功能页面看到这段文字)
notificationTimeout:响应时间间隔,设为100
packageNames:需要辅助的app包名,默认是所有app
当然,除了提供配置文件来配置辅助服务了参数之外,还可以通过代码来配置,具体参考:
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
} catch (Exception e) {
Log.i(TAG, "start ACTION_ACCESSIBILITY_SETTINGS fail: " + e.getMessage());
startActivity(new Intent(Settings.ACTION_SETTINGS));
} finally {
finish();
}
}
}
在MainActivity中检查并跳转到辅助功能界面,提示用户打开辅助功能开关。
public class SimulatedClickService extends AccessibilityService {
private static final String TAG = SimulatedClickService.class.getSimpleName();
private Handler handler = new Handler(Looper.getMainLooper()) {
@TargetApi(Build.VERSION_CODES.N)
@Override
public void handleMessage(Message msg) {
dispatchGestureClick(160, 60);
}
};
/**
* 监听窗口变化的回调
*
* @param event 窗口变化事件
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
int eventType = event.getEventType();
Log.i(TAG, "onAccessibilityEvent: " + eventType);
switch (eventType) {
// 通知栏发生变化
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
// 模拟点击通知栏,因为通知栏弹出有动画,所以需要延迟
handler.sendEmptyMessageDelayed(0, 1500);
break;
default:
}
}
@RequiresApi(24)
public void dispatchGestureClick(int x, int y) {
Path path = new Path();
path.moveTo(x, y);
boolean click = dispatchGesture(new GestureDescription
.Builder()
.addStroke(new GestureDescription.StrokeDescription(path, 0, 100)).build(),null, null);
Log.i(TAG, "dispatchGestureClick: " + click);
}
/**
* 中断服务的回调
*/
@Override
public void onInterrupt() {
}
/**
* 当服务启动时的回调,可以做一些初始化操作
*/
@Override
protected void onServiceConnected() {
super.onServiceConnected();
}
}
上面这段代码关键的地方在于onAccessibilityEvent,通过event.getEventType()来得知响应到了什么事件,从而执行相应的逻辑。
Github:
转载: