يواجه العديد من مستخدمي Android مواقف مختلفة تدفعهم إلى التفاعل مع هواتفهم بطرق مختلفة. بالنسبة للمستخدمين غير القادرين على استخدام الهواتف الذكية التي تعمل بنظام Android بسبب الرؤية أو السمع أو لأسباب جسدية أخرى، يوفر Android وظائف وخدمات إمكانية الوصول لمساعدة هؤلاء المستخدمين على تشغيل الجهاز بشكل أكثر بساطة، بما في ذلك تحويل النص إلى كلام، والتعليقات اللمسية، وتشغيل الإيماءات، وكرة التتبع. والتعامل مع العملية. يمكن للمطورين إنشاء خدمات إمكانية الوصول الخاصة بهم، والتي يمكن أن تعزز سهولة استخدام التطبيقات، مثل المطالبات الصوتية والملاحظات المادية وأوضاع التشغيل الاختيارية الأخرى.
يتمثل تنفيذه المحدد في التشغيل في الخلفية من خلال خدمة AccessibilityService وتلقي عمليات الاسترجاعات لأحداث محددة من خلال AccessibilityEvent. تمثل مثل هذه الأحداث بعض انتقالات الحالة التي يمر بها المستخدم في الواجهة، مثل: تغيير التركيز، أو النقر على زر، وما إلى ذلك. قد تتمتع هذه الخدمات بشكل اختياري بالقدرة على طلب محتويات النافذة النشطة. ببساطة، AccessibilityService هي خدمة مراقبة في الخلفية. عندما يتغير المحتوى الذي تراقبه، سيتم استدعاء طريقة رد الاتصال لخدمة الخلفية.
اكتب فئة الخدمة الخاصة بك وتجاوز طريقة onServiceConnected () وطريقة onAccessibilityEvent () وطريقة onInterrupt ()
public class QHBAccessibilityService extends AccessibilityService {
/**
* 当启动服务的时候就会被调用
*/
@ Override
protected void onServiceConnected () {
super . onServiceConnected ();
}
/**
* 监听窗口变化的回调
*/
@ Override
public void onAccessibilityEvent ( AccessibilityEvent event ) {
int eventType = event . getEventType ();
//根据事件回调类型进行处理
}
/**
* 中断服务的回调
*/
@ Override
public void onInterrupt () {
}
}
فيما يلي مقدمة للطرق شائعة الاستخدام في AccessibilityService
نظرًا لأنها خدمة في الخلفية، فنحن بحاجة إلى تكوين معلومات الخدمة في البيانات
< service
android : name = " .AccessibilityService.QHBAccessibilityService "
android : enabled = " true "
android : exported = " true "
android : label = " @string/label "
android : permission = " android.permission.BIND_ACCESSIBILITY_SERVICE " >
< intent-filter >
< action android : name = " android.accessibilityservice.AccessibilityService " />
</ intent-filter >
</ service >
يجب أن ننتبه: أي خطأ في تكوين المعلومات سيجعل الخدمة غير مستجيبة
يشير تكوين معلمات الخدمة إلى: التكوين لقبول أحداث من أنواع محددة، والاستماع إلى الحزم المحددة، واسترداد محتوى النافذة، والحصول على وقت أنواع الأحداث، وما إلى ذلك. هناك طريقتان لتكوين معلمات الخدمة:
أضف علامة البيانات الوصفية إلى البيان الأصلي لتحديد ملف XML
< service
android : name = " .AccessibilityService.QHBAccessibilityService "
android : enabled = " true "
android : exported = " true "
android : label = " @string/label "
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/accessibility_service_config " />
</ service >
التالي هو تكوين ملف Accessibility_service_config
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< accessibility-service xmlns : android = " http://schemas.android.com/apk/res/android "
android : accessibilityEventTypes = " typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged|typeWindowsChanged "
android : accessibilityFeedbackType = " feedbackGeneric "
android : accessibilityFlags = " flagDefault "
android : canRetrieveWindowContent = " true "
android : description = " @string/description "
android : notificationTimeout = " 100 "
android : packageNames = " com.tencent.mm " />
فيما يلي مقدمة لمعلمات XML
AccessibilityEventTypes: يشير إلى التغييرات في الواجهة التي تهتم بها الخدمة، أي الأحداث التي يتم الإخطار بها، مثل فتح النافذة، والانزلاق، وتغيير التركيز، والضغط لفترة طويلة، وما إلى ذلك. يمكن العثور على القيمة المحددة في فئة AccessibilityEvent، على سبيل المثال، typeAllMask يعني قبول جميع إشعارات الأحداث.
إمكانية الوصولFeedbackType: يشير إلى طريقة تقديم الملاحظات، مثل تشغيل الصوت أو الاهتزاز
canRetrieveWindowContent: يشير إلى ما إذا كان بإمكان الخدمة الوصول إلى المحتوى الموجود في النافذة النشطة. أي، إذا كنت ترغب في الحصول على محتوى النموذج في الخدمة، فأنت بحاجة إلى تعيين قيمته على true
description: وصف لميزة إمكانية الوصول، كما هو موضح في الشكل أدناه
notificationTimeout: الفاصل الزمني لقبول الأحداث، وعادةً ما يتم ضبطه على 100
packageNames: يشير إلى الحزمة التي تستخدمها الخدمة لمراقبة الأحداث. هنا نأخذ اسم حزمة WeChat كمثال.
قم بتكوين معلومات AccessibilityServiceInfo لخدمة AccessibilityService الخاصة بنا من خلال الكود. هنا يمكننا استخراجها في طريقة للإعداد
private void settingAccessibilityInfo () {
String [] packageNames = { "com.tencent.mm" };
AccessibilityServiceInfo mAccessibilityServiceInfo = new AccessibilityServiceInfo ();
// 响应事件的类型,这里是全部的响应事件(长按,单击,滑动等)
mAccessibilityServiceInfo . eventTypes = AccessibilityEvent . TYPES_ALL_MASK ;
// 反馈给用户的类型,这里是语音提示
mAccessibilityServiceInfo . feedbackType = AccessibilityServiceInfo . FEEDBACK_SPOKEN ;
// 过滤的包名
mAccessibilityServiceInfo . packageNames = packageNames ;
setServiceInfo ( mAccessibilityServiceInfo );
}
يتم استخدام فئة AccessibilityServiceInfo هنا. يتم استخدام فئة AccessibilityServiceInfo لتكوين معلومات AccessibilityService. تحتوي هذه الفئة على عدد كبير من الحقول الثابتة لخصائص التكوين وXML، وتشمل هذه الحقول الشائعة: AccessibilityEventTypes وcanRequestFilterKeyEvents وpackageNames وما إلى ذلك.
نحتاج هنا إلى تشغيل هذه الوظيفة يدويًا في وظيفة إمكانية الوصول، وإلا فلن نتمكن من الاستمرار. يمكنك فتح قائمة وظائف إمكانية الوصول للنظام من خلال الكود التالي
Intent intent = new Intent ( Settings . ACTION_ACCESSIBILITY_SETTINGS );
startActivity ( intent );
نظرًا لأننا نراقب شريط الإعلام وواجهة الحدث، فعندما يتغير شريط الإعلام أو واجهة أسماء الحزم المحددة، سيتم استدعاء حدثنا مرة أخرى من خلال onAccessibilityEvent، ثم ستتم معالجة الحدث.
@ Override
public void onAccessibilityEvent ( AccessibilityEvent event ) {
int eventType = event . getEventType ();
//根据事件回调类型进行处理
switch ( eventType ) {
//当通知栏发生改变时
case AccessibilityEvent . TYPE_NOTIFICATION_STATE_CHANGED :
break ;
//当窗口的状态发生改变时
case AccessibilityEvent . TYPE_WINDOW_STATE_CHANGED :
break ;
}
}
عندما نتلقى إشعارًا على WeChat، ستصل رسالة دفع في شريط الحالة في هذا الوقت، ستتم مراقبتها بواسطة TYPE_NOTIFICATION_STATE_CHANGED وسيتم تنفيذ المحتوى الموجود بداخلها عندما نقوم بتبديل واجهة WeChat أو استخدام WeChat، سيتم ذلك هذه المرة تتم مراقبته بواسطة TYPE_WINDOW_STATE_CHANGED وتنفيذ المحتوى بالداخل
طرق إمكانية الوصول إلى الحدث
بعد الحصول على تغييرات نافذة الواجهة، من الضروري الحصول على عقد التحكم في هذا الوقت. عقد النافذة بأكملها هي في الأساس بنية شجرة، ويتم تشغيل معلومات العقدة من خلال ما يلي
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow ();
//通过文本找到对应的节点集合
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByText ( text );
//通过控件ID找到对应的节点集合,如com.tencent.mm:id/gd
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByViewId ( clickId );
بعد أن نحصل على معلومات العقدة، يمكننا إجراء نقرات محاكاة وضغطات طويلة وعمليات أخرى على عقد التحكم. توفر فئة AccessibilityNodeInfo طريقة الأداء () للسماح لنا بإجراء عمليات محاكاة، يرجى الرجوع إلى الوثائق الرسمية يتم سرد العمليات شائعة الاستخدام هنا.
//模拟点击
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_CLICK );
//模拟长按
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_LONG_CLICK );
//模拟获取焦点
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_FOCUS );
//模拟粘贴
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_PASTE );
عندما يكون هاتفنا متصلاً بكابل USB، حدد الجهاز في Android Device Monitor وافتح أداة Dump View Hierarchy for UI Automator، والتي يمكننا من خلالها الحصول على معلومات التحكم
س:
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
يُبلغ دائمًا عن مؤشر فارغ هل واجه المدون هذه المشكلة ج: لقد واجهت أيضًا مشكلة مثل مشكلتك، وأعتقد أنها موجودة في "معلمات خدمة التكوين". "، لكنه لم يحدث. لقد وجدت الإعداد المطابق لـ android:canRetrieveWindowContent="true"، لذلك قمت بتغييره لتكوينه في ملف xml، وكان الأمر جيدًا.
س: كيف يمكنك الحصول على أسماء الفئات هذه com.tencent.mm.ui.LauncherUI؟ ج: String className = events.getClassName().toString(); استخدم السجل لطباعته، وافتح WeChat لعرض معلومات السجل
النص الأصلي: مدونة Hensen_