Android进阶 - 监视活动窗口

摘要

在Android程序的开发维护过程中,我们可能经常需要知道自己所看到的界面处于哪一个Activity中,相信大部分程序员的做法是“在基类里打Log”,很传统没毛病o(╯□╰)o….

前几天,在应用宝的应用商店内发现了一个很有意思的APP – 当前Activity,可以显示出当前界面上显示的 应用包名Activity类名。然后,一直很好奇是如何实现的,最近抽时间研究了一下。

下面是研究成果:

《Android进阶 - 监视活动窗口》 image_example.png

开源项目CurrentActivity地址:

https://github.com/sinawangnan7/CurrentActivity

欢迎Star…(๑•̀ㅂ•́)و✧

正文

本文主要讲述两部分内容:

1、CurrentActivity的使用场景

2、CurrentActivity的实现思路

CurrentActivity的使用场景

1、定位自己APP的页面,获取类名称

这应该是我们经常碰到的问题,测试人员经常拿着出Bug的页面询问“开发人员”,如果这个页面还不是“此开发人员”写的,估计查起来就费劲了。此工具能帮助开发人员提高查找效率。

2、分析其他APP命名及功能

可以查看其他APP的页面路径和命名,给自己开发做个参考(下面以微信支付宝为例)。

(1) 微信

《Android进阶 - 监视活动窗口》 wx.png

观察上图,可以看到 微信 的Activity在命名时是以 “UI” 为后缀进行标识的,类在分包时也放在了ui包目录下。另外,还有一个比较有意思的发现,微信的“主界面”和“聊天界面”用的是同一个Activity

(2) 支付宝

《Android进阶 - 监视活动窗口》 alipay.png

笔者公司开发的APP和支付宝APP类似,也是做 互联网金融 的。所以,产品经理在设计功能和流程时经常会“参考”支付宝是如何实现的,比如需要确定 哪些页面用原生做,哪些需要用H5来做。但是,支付宝的原生和H5在使用体验上很难感知出来(这里支付宝做得很赞),这时这个工具就可以派上用场了,支付宝展示H5的页面用的是H5Activity

最近,笔者需要做一个类似支付宝的支付键盘,一开始以为是纯Dialog实现的,最后发现实际上用Activity包了一层。这其实也并不意外,第三方APP在吊起“支付宝支付”时,用户如果安装了支付宝,吊起的也是这个FlyBirdWindowActivity。

CurrentActivity的实现思路

这个监视活动的窗口是如何实现的?

本文只讲述 思路和核心代码,完整代码请参看GitHub开源项目:
CurrentActivity

实现这个监视窗口需要解决两个问题:

  • 1、如何向界面顶部添加一个显示窗口?

  • 2、如何监听应用切换、Activity切换?

第一个问题很简单,通过WindowManager添加一个TextView即可, 但是需要注意下悬浮窗权限问题,这个问题很多博客都给出了解决方案,笔者简单说下,就不在赘述了。

笔者做了一个简单的窗口视图管理器:

完整代码:WindowViewContainer.java

创建窗口的核心代码如下:

/**
 * 添加窗口视图
 */
private void addView() {
    // 创建布局参数
    mParams = new WindowManager.LayoutParams();
    // 获取窗口管理器
    mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    // 设置类型
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // Android O 以上,使用TYPE_APPLICATION_OVERLAY弹窗类型
        mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
    } else {
        // Android O 以下,使用TYPE_SYSTEM_ALERT弹窗类型
        mParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
    }
    // 设置标签(FLAG_NOT_FOCUSABLE表示窗口不会获取焦点;FLAG_NOT_TOUCHABLE表示窗口不会接收Touch事件,即将Touch事件向下层分发)
    mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    // 设置位图模式 (PixelFormat.RGBA_8888可以使背景透明。不设置默认PixelFormat.OPAQUE,即不透明)
    mParams.format = PixelFormat.RGBA_8888;
    // 设置分布位置(距左对齐 + 距顶对齐)
    mParams.gravity = Gravity.LEFT | Gravity.TOP;
    // 设置布局宽/高为自适应
    mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
    mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
    // 添加TextView
    mWindowManager.addView(mTextView, mParams);
    // 记录视图已被添加、显示
    isAdded = true;
    isShow = true;
}

提醒:
1.注意悬浮窗权限问题,可参考 AndroidManifest.xml 中的权限声明。
2.适配Android 8.0,请使用TYPE_APPLICATION_OVERLAY弹窗类型。

第二个问题:如何监听应用切换、Activity切换?笔者查了很长时间,最后发现了一个叫 AccessibilityService(辅助服务)的东西,了解完 AccessibilityService 感觉好像发现了新大陆,其实这个“辅助服务”使用最为出名的是“微信自动抢红包插件”。但是,今天笔者只是简单介绍下AccessibilityService(辅助服务)的入门使用 – 监听窗口改变

辅助服务创建步骤及使用流程

1.创建自定义AccessibilityService,核心代码如下:

/**
 * @ClassName: MAccessibilityService
 * @Description: 辅助服务
 * @Author wangnan7
 * @Date: 2018/4/1
 */

public class MAccessibilityService extends AccessibilityService {

    ......

    /**
     * 服务连接完成
     */
    @Override
    protected void onServiceConnected() {
        // 添加窗口
        mWindowViewContainer = WindowViewContainer.getInstance(this);
        mWindowViewContainer.addWindowView();
        ......
    }

    ......

    /**
     * 接收辅助服务事件
     */
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event == null) {
            return;
        }
        switch (event.getEventType()) {
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: // 窗口状态改变
                if (event.getPackageName() != null && event.getClassName() != null) {
                    // 更新窗口视图
                    mWindowViewContainer.updateWindowView(event.getPackageName() + "\n" + event.getClassName());
                }
                break;
            default:
                break;
        }
    }

    /**
     * 服务中断
     */
    @Override
    public void onInterrupt() {
    }


    /**
     * 服务退出
     */
    @Override
    public void onDestroy() {
        // 移除窗口,销毁视图容器
        mWindowViewContainer.destory();
        ......
    }
}

完整代码:MAccessibilityService.java

整个功能的核心都在onAccessibilityEvent(AccessibilityEvent event)这个方法中,如果开启辅助服务,只要服务不死,进程不挂,当前窗口的每次改变我们都能监听到。(如果你查看了完整代码,会看到笔者添加了一个Notification,把辅助服务提升为了前台服务,这么做只是简单的做下服务保活)

2.在AndroidManifest.xml文件中声明该服务, 核心代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wangnan.currentactivity">

    ......

    <application
        
        ......

        <!-- 辅助服务 -->
        <service
            android:name=".service.MAccessibilityService"
            android:label="当前Activity(辅助工具)"
            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>
        ......
    </application>

</manifest>

完整代码:AndroidManifest.xml

详细说下辅助服务的配置声明:

1.android:name 用于指定服务名称,前面加“.”表示书写时省略掉了包名。

2.android:lable 用于指定外部显示的服务名称。

3.android:permission 表明服务向系统请求那些权限

4.intent-filteraction 表明传递给该服务的哪些Intent需要过滤出来进行处理

可能会有人疑问为什么要配置3和4,其实这是源码文档要求的,是必须配置的,如下图所示:

《Android进阶 - 监视活动窗口》 source_code.png

5.meta-data 元数据,用于配置辅助服务的详情信息

其实这一项在manifest文件中是可配可不配的,只是文档支持在manifest文件里进行配置,如果不在这配置就需要到辅助服务的Java代码里去配置了,源码解释如下:

《Android进阶 - 监视活动窗口》 source_code2.png

接下来,看下笔者的元数据配置文件(android:resource=”@xml/accessibility”)

完整代码:accessibility.xml

元数据配置文件说明,如下图所示:

《Android进阶 - 监视活动窗口》 source_code3.png

3.开启辅助服务

开启辅助服务不能用startService()这种方式打开,因为使用辅助服务是有一定风险的,需要用户主动授权(同意开启)

辅助服务打开流程:

安装APP(含有辅助服务) -> 辅助功能 -> 服务(点击需要开启的服务) -> 开启

以笔者的手机(360N5)和 CurrentActivity 为例,打开流程如下图所示:

《Android进阶 - 监视活动窗口》 image_open.png

4.关闭辅助服务

辅助功能 -> 服务(点击需要关闭的服务) -> 关闭

以笔者的手机(360N5)和 CurrentActivity 为例,关闭流程如下图所示:

《Android进阶 - 监视活动窗口》 image_close.png

CurrentActivity的详细使用方法和源码请参看Github:

https://github.com/sinawangnan7/CurrentActivity

其他

1.AccessibilityService位于在系统设置里,有些手机翻译成“辅助服务”,有些手机翻译成“无障碍”

2.AccessibilityService被用户授权开启后并不是一直保活的,也有可能被系统销毁。

题外话

辅助服务其实还有很多使用场景。比如,从上图笔者手机应用列表里看到的云服务360手机助手(下载自动安装)、京东金融(手环社交软件提醒)。另外,还有我们经常听说的微信自动抢红包微信自动回复…各位如果有兴趣可以研究下。Good Luck~

最后的福利(2018年4月16号添加):
写完这篇博客后,笔者又研究了下微信抢红包原理,写了一个【微信自动抢红包】插件,原理也是使用辅助服务,开源项目地址:
https://github.com/sinawangnan7/WXGiftMoney
欢迎Star…(๑•̀ㅂ•́)و✧

    原文作者:梦想编织者灬小楠
    原文地址: https://www.jianshu.com/p/869e7c4c3b89
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞