如何阅读窗口内容(使用accessibilityService)并使用绘制来激活UI而不是Android中的其他应用程序权限?

Ume*_*han 22 java android accessibility accessibilityservice android-accessibility

我关于同一主题的最后一个问题不够明确,并被社区搁置,后来被自动删​​除.所以,我正在以详细的方式解释该问题,以便社区能够以更好的方式理解和帮助.

我想要类似于Voodoo AppMySmartPrice优惠的功能.

现在他们做了什么

第1步:当我们第一次打开Voodoo应用程序时,他们会显示一个小教程.在教程结束时,有一个"立即激活"按钮,按下后,将我们带到辅助功能设置屏幕.

第2步:在辅助功能屏幕中,它进一步指导如何查找和无法使用Voodoo服务.

第3步:当我们启用它时,它还要求授予"观察您的操作"和"检索窗口内容"权限.

第4步:完成授予可访问性屏幕权限,移动到某个购物应用程序或通过浏览器访问购物网站并到达产品页面后,将自动弹出voodoo浮动按钮.

第5步:点击它后,它会显示其他应用或网站上可用的相同/相关/类似产品的价格,以便用户可以检查最佳可用交易.

参考Voodoo的屏幕截图

巫毒屏幕1

辅助功能屏幕

辅助功能屏幕2

权限授予屏幕

巫毒屏幕2

产品页面上的巫毒浮动按钮

Voodoo结果借助于绘制其他应用程序

现在我想知道形式社区:

  1. 如何在"辅助功能"屏幕和产品详细信息页面上显示我的帮助UI.
  2. 如何检测产品页面何时出现在屏幕上并唤起我的浮动按钮.
  3. 如何获取屏幕上显示的产品名称.
  4. 如何仅为某些应用限制此屏幕阅读功能?(因为我不想在某些版权问题上结束)
  5. 有没有可以帮助我的教程?虽然我已经尝试过谷歌的任何直接教程,但没有取得任何成功.

现在为什么我需要这些信息:

我正计划为学生提供一个应用程序,如果它可以在我的服务器上或在一些可用的网站上,它们将帮助他们免费获得所需(或类似)书籍(电子书).我想仅限于某些应用程序的功能,因为某些书籍的版权问题.

现在我从我的研究中了解到这个主题(但我不确定我是否在正确的轨道上)

Ume*_*han 26

我试图总结一下我是如何在博客文章中解决问题的.任何需要帮助的人都可以查看.

无障碍服务更上一层楼

我之前的回答被主持人删除可能是因为我刚刚发布了一个指向博客的链接.所以我也在这里再次发布我的答案.

最简单的方法是由android本身提供.如果您在自己的应用程序上构建一些东西,这是最好和最简单的方法.您必须使用"findAccessibilityNodeInfosByViewId()",如下所述

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    AccessibilityNodeInfo source = event.getSource(); 
    if (source == null) {
        return; 
    } 
    List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId = source.findAccessibilityNodeInfosByViewId("YOUR PACKAGE NAME:id/RESOURCE ID FROM WHERE YOU WANT DATA"); 
    if (findAccessibilityNodeInfosByViewId.size() > 0) {
        AccessibilityNodeInfo parent = (AccessibilityNodeInfo) findAccessibilityNodeInfosByViewId.get(0);
        // You can also traverse the list if required data is deep in view hierarchy. 
        String requiredText = parent.getText().toString();
        Log.i("Required Text", requiredText);
    }
}  
Run Code Online (Sandbox Code Playgroud)

如果您在其他应用程序上构建某些内容并且不知道res id.您必须使用父,子计数,找到数据的级别,事件类型的组合来构建逻辑.您必须在事件或来源中查找模式或上述所述值的组合以获得所需的数据.此外,您必须在代码中设置一些调整,以根据您的任务获得准确的数据.就像我们的任务一样,我们有一些正则表达式来获取宝贵的数据.

您必须注意,如果更改视图或UI或更改了res,则当前逻辑可能会失败.因此,您必须密切关注构建服务的应用程序.下面是一些示例代码,我们在其中获取没有res id的数据,这可能对您了解它将如何工作很有用.

打印源和事件

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    AccessibilityNodeInfo source = event.getSource();
    if (source == null) {
        return;
    } 
    Log.i("Event", event.toString() + ""); 
    Log.i("Source", source.toString() + "");
}
Run Code Online (Sandbox Code Playgroud)

获得子计数

source.getChildCount();
Run Code Online (Sandbox Code Playgroud)

如果子计数> 0,您可能需要查看它.

示例代码1

if (level == 0 && source.getClassName().equals("android.widget.TextView") && source.getText()!=null && !source.getText().toString().isEmpty()){
    // here level is iteration of for loop
    String recivedText = source.getText().toString(); 
    if(source.getClassName().equals("android.widget.TextView") && source.getParent()!=null && source.getParent().getClassName().equals("android.widget.FrameLayout") && source.getParent().getParent()==null){ 
        return recivedText;
    }
}
Run Code Online (Sandbox Code Playgroud)

示例代码2

if (source.getPackageName().equals("PACKAGE NAME OF APP FOR WHICH YOUR EXPECTING EVENT")) {
    if(event.getEventType()==AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && "COMPLETE NAME OF ACTIVITY CLASS WITH PACKAGE NAME (if you want it for some specific screen)".equals(event.getClassName())){
        if(source.getText()!=null && source.getClassName().equals("android.widget.TextView") && source.getParent()!=null && source.getParent().getClassName().equals("android.widget.RelativeLayout")&& source.getParent().getParent()!=null && source.getParent().getParent().getClassName().equals("android.widget.ScrollView") && source.getParent().getParent().getParent()!=null && source.getParent().getParent().getParent().getClassName().equals("android.support.v4.view.ViewPager")&& source.getParent().getParent().getParent().getParent()!=null && source.getParent().getParent().getParent().getParent().getClassName().equals("android.widget.FrameLayout")&& source.getParent().getParent().getParent().getParent().getParent()==null){
        return source.getText().toString();
        }
}
Run Code Online (Sandbox Code Playgroud)

它有点笨拙,但要让它工作,你必须深入研究日志,找到一个模式,它将带你到你需要的数据.

更新20/11/2017 Google正在暂停使用辅助功能服务的所有应用程序,以用于辅助功能之外的其他功能.我收到了一封关于我的应用程序的电子邮件,其他开发者也收到了来自谷歌(Reddit)的同一封电子邮件.所以,我认为我们应该寻找其他一些做事方式,我也请你在这里更新它,如果有人提出其他实现来实现相同的行为,它也会帮助其他人.

谢谢Umesh Chauhan