Android進(jìn)階 - 監(jiān)視活動窗口

摘要

在Android程序的開發(fā)維護(hù)過程中宋光,我們可能經(jīng)常需要知道自己所看到的界面處于哪一個Activity中勒极,相信大部分程序員的做法是“在基類里打Log”,很傳統(tǒng)沒毛病o(╯□╰)o....

前幾天茂浮,在應(yīng)用寶的應(yīng)用商店內(nèi)發(fā)現(xiàn)了一個很有意思的APP - 當(dāng)前Activity菌羽,可以顯示出當(dāng)前界面上顯示的 應(yīng)用包名Activity類名。然后壮不,一直很好奇是如何實現(xiàn)的汗盘,最近抽時間研究了一下。

下面是研究成果:

image_example.png

開源項目CurrentActivity地址:

https://github.com/sinawangnan7/CurrentActivity

歡迎Star...(??????)??

正文

本文主要講述兩部分內(nèi)容:

1忆畅、CurrentActivity的使用場景

2衡未、CurrentActivity的實現(xiàn)思路

CurrentActivity的使用場景

1尸执、定位自己APP的頁面家凯,獲取類名稱

這應(yīng)該是我們經(jīng)常碰到的問題,測試人員經(jīng)常拿著出Bug的頁面詢問“開發(fā)人員”如失,如果這個頁面還不是“此開發(fā)人員”寫的绊诲,估計查起來就費勁了。此工具能幫助開發(fā)人員提高查找效率褪贵。

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

可以查看其他APP的頁面路徑和命名抗俄,給自己開發(fā)做個參考(下面以微信支付寶為例)。

(1) 微信

wx.png

觀察上圖世舰,可以看到 微信 的Activity在命名時是以 "UI" 為后綴進(jìn)行標(biāo)識的动雹,類在分包時也放在了ui包目錄下。另外跟压,還有一個比較有意思的發(fā)現(xiàn)胰蝠,微信的“主界面”和“聊天界面”用的是同一個Activity

(2) 支付寶

alipay.png

筆者公司開發(fā)的APP和支付寶APP類似震蒋,也是做 互聯(lián)網(wǎng)金融 的茸塞。所以,產(chǎn)品經(jīng)理在設(shè)計功能和流程時經(jīng)常會“參考”支付寶是如何實現(xiàn)的查剖,比如需要確定 哪些頁面用原生做钾虐,哪些需要用H5來做。但是笋庄,支付寶的原生和H5在使用體驗上很難感知出來(這里支付寶做得很贊)效扫,這時這個工具就可以派上用場了,支付寶展示H5的頁面用的是H5Activity直砂。

最近荡短,筆者需要做一個類似支付寶的支付鍵盤,一開始以為是純Dialog實現(xiàn)的哆键,最后發(fā)現(xiàn)實際上用Activity包了一層掘托。這其實也并不意外,第三方APP在吊起“支付寶支付”時籍嘹,用戶如果安裝了支付寶闪盔,吊起的也是這個FlyBirdWindowActivity。

CurrentActivity的實現(xiàn)思路

這個監(jiān)視活動的窗口是如何實現(xiàn)的辱士?

本文只講述 思路和核心代碼仪糖,完整代碼請參看GitHub開源項目:
CurrentActivity

實現(xiàn)這個監(jiān)視窗口需要解決兩個問題:

  • 1、如何向界面頂部添加一個顯示窗口军浆?

  • 2返敬、如何監(jiān)聽?wèi)?yīng)用切換、Activity切換头岔?


第一個問題很簡單塔拳,通過WindowManager添加一個TextView即可, 但是需要注意下懸浮窗權(quán)限問題,這個問題很多博客都給出了解決方案峡竣,筆者簡單說下靠抑,就不在贅述了。

筆者做了一個簡單的窗口視圖管理器:

完整代碼:WindowViewContainer.java

創(chuàng)建窗口的核心代碼如下:

/**
 * 添加窗口視圖
 */
private void addView() {
    // 創(chuàng)建布局參數(shù)
    mParams = new WindowManager.LayoutParams();
    // 獲取窗口管理器
    mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    // 設(shè)置類型
    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;
    }
    // 設(shè)置標(biāo)簽(FLAG_NOT_FOCUSABLE表示窗口不會獲取焦點荠列;FLAG_NOT_TOUCHABLE表示窗口不會接收Touch事件,即將Touch事件向下層分發(fā))
    mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    // 設(shè)置位圖模式 (PixelFormat.RGBA_8888可以使背景透明载城。不設(shè)置默認(rèn)PixelFormat.OPAQUE肌似,即不透明)
    mParams.format = PixelFormat.RGBA_8888;
    // 設(shè)置分布位置(距左對齊 + 距頂對齊)
    mParams.gravity = Gravity.LEFT | Gravity.TOP;
    // 設(shè)置布局寬/高為自適應(yīng)
    mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
    mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
    // 添加TextView
    mWindowManager.addView(mTextView, mParams);
    // 記錄視圖已被添加、顯示
    isAdded = true;
    isShow = true;
}

提醒:
1.注意懸浮窗權(quán)限問題诉瓦,可參考 AndroidManifest.xml 中的權(quán)限聲明锈嫩。
2.適配Android 8.0,請使用TYPE_APPLICATION_OVERLAY彈窗類型垦搬。


第二個問題:如何監(jiān)聽?wèi)?yīng)用切換呼寸、Activity切換?筆者查了很長時間猴贰,最后發(fā)現(xiàn)了一個叫 AccessibilityService(輔助服務(wù))的東西对雪,了解完 AccessibilityService 感覺好像發(fā)現(xiàn)了新大陸,其實這個“輔助服務(wù)”使用最為出名的是“微信自動搶紅包插件”米绕。但是瑟捣,今天筆者只是簡單介紹下AccessibilityService(輔助服務(wù))的入門使用 - 監(jiān)聽窗口改變


輔助服務(wù)創(chuàng)建步驟及使用流程

1.創(chuàng)建自定義AccessibilityService栅干,核心代碼如下:

/**
 * @ClassName: MAccessibilityService
 * @Description: 輔助服務(wù)
 * @Author wangnan7
 * @Date: 2018/4/1
 */

public class MAccessibilityService extends AccessibilityService {

    ......

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

    ......

    /**
     * 接收輔助服務(wù)事件
     */
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event == null) {
            return;
        }
        switch (event.getEventType()) {
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: // 窗口狀態(tài)改變
                if (event.getPackageName() != null && event.getClassName() != null) {
                    // 更新窗口視圖
                    mWindowViewContainer.updateWindowView(event.getPackageName() + "\n" + event.getClassName());
                }
                break;
            default:
                break;
        }
    }

    /**
     * 服務(wù)中斷
     */
    @Override
    public void onInterrupt() {
    }


    /**
     * 服務(wù)退出
     */
    @Override
    public void onDestroy() {
        // 移除窗口迈套,銷毀視圖容器
        mWindowViewContainer.destory();
        ......
    }
}

完整代碼:MAccessibilityService.java

整個功能的核心都在onAccessibilityEvent(AccessibilityEvent event)這個方法中,如果開啟輔助服務(wù)碱鳞,只要服務(wù)不死桑李,進(jìn)程不掛,當(dāng)前窗口的每次改變我們都能監(jiān)聽到窿给。(如果你查看了完整代碼贵白,會看到筆者添加了一個Notification,把輔助服務(wù)提升為了前臺服務(wù)崩泡,這么做只是簡單的做下服務(wù)苯模活)


2.在AndroidManifest.xml文件中聲明該服務(wù), 核心代碼如下:

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

    ......

    <application
        
        ......

        <!-- 輔助服務(wù) -->
        <service
            android:name=".service.MAccessibilityService"
            android:label="當(dāng)前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

詳細(xì)說下輔助服務(wù)的配置聲明:

1.android:name 用于指定服務(wù)名稱,前面加“.”表示書寫時省略掉了包名角撞。

2.android:lable 用于指定外部顯示的服務(wù)名稱呛伴。

3.android:permission 表明服務(wù)向系統(tǒng)請求那些權(quán)限

4.intent-filteraction 表明傳遞給該服務(wù)的哪些Intent需要過濾出來進(jìn)行處理

可能會有人疑問為什么要配置3和4,其實這是源碼文檔要求的谒所,是必須配置的热康,如下圖所示:

source_code.png

5.meta-data 元數(shù)據(jù),用于配置輔助服務(wù)的詳情信息

其實這一項在manifest文件中是可配可不配的百炬,只是文檔支持在manifest文件里進(jìn)行配置褐隆,如果不在這配置就需要到輔助服務(wù)的Java代碼里去配置了污它,源碼解釋如下:

source_code2.png

接下來剖踊,看下筆者的元數(shù)據(jù)配置文件(android:resource="@xml/accessibility")

完整代碼:accessibility.xml

元數(shù)據(jù)配置文件說明庶弃,如下圖所示:

source_code3.png

3.開啟輔助服務(wù)

開啟輔助服務(wù)不能用startService()這種方式打開,因為使用輔助服務(wù)是有一定風(fēng)險的德澈,需要用戶主動授權(quán)(同意開啟)歇攻。

輔助服務(wù)打開流程:

安裝APP(含有輔助服務(wù)) -> 輔助功能 -> 服務(wù)(點擊需要開啟的服務(wù)) -> 開啟

以筆者的手機(jī)(360N5)和 CurrentActivity 為例,打開流程如下圖所示:

image_open.png

4.關(guān)閉輔助服務(wù)

輔助功能 -> 服務(wù)(點擊需要關(guān)閉的服務(wù)) -> 關(guān)閉

以筆者的手機(jī)(360N5)和 CurrentActivity 為例梆造,關(guān)閉流程如下圖所示:

image_close.png

CurrentActivity的詳細(xì)使用方法和源碼請參看Github:

https://github.com/sinawangnan7/CurrentActivity

其他

1.AccessibilityService位于在系統(tǒng)設(shè)置里缴守,有些手機(jī)翻譯成“輔助服務(wù)”,有些手機(jī)翻譯成“無障礙”镇辉。

2.AccessibilityService被用戶授權(quán)開啟后并不是一直甭潘耄活的,也有可能被系統(tǒng)銷毀忽肛。

題外話

輔助服務(wù)其實還有很多使用場景村砂。比如,從上圖筆者手機(jī)應(yīng)用列表里看到的云服務(wù)屹逛、360手機(jī)助手(下載自動安裝)础废、京東金融(手環(huán)社交軟件提醒)。另外罕模,還有我們經(jīng)常聽說的微信自動搶紅包评腺、微信自動回復(fù)...各位如果有興趣可以研究下。Good Luck~

最后的福利(2018年4月16號添加):
寫完這篇博客后淑掌,筆者又研究了下微信搶紅包原理蒿讥,寫了一個【微信自動搶紅包】插件,原理也是使用輔助服務(wù)抛腕,開源項目地址:
https://github.com/sinawangnan7/WXGiftMoney
歡迎Star...(??????)??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诈悍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子兽埃,更是在濱河造成了極大的恐慌侥钳,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柄错,死亡現(xiàn)場離奇詭異舷夺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)售貌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門给猾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颂跨,你說我怎么就攤上這事敢伸。” “怎么了恒削?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵池颈,是天一觀的道長尾序。 經(jīng)常有香客問我,道長躯砰,這世上最難降的妖魔是什么每币? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮琢歇,結(jié)果婚禮上兰怠,老公的妹妹穿的比我還像新娘。我一直安慰自己李茫,他們只是感情好揭保,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著魄宏,像睡著了一般掖举。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娜庇,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天塔次,我揣著相機(jī)與錄音,去河邊找鬼名秀。 笑死励负,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的匕得。 我是一名探鬼主播继榆,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼汁掠!你這毒婦竟也來了略吨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤考阱,失蹤者是張志新(化名)和其女友劉穎翠忠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乞榨,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡秽之,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了吃既。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片考榨。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鹦倚,靈堂內(nèi)的尸體忽然破棺而出河质,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布掀鹅,位于F島的核電站散休,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏淫半。R本人自食惡果不足惜溃槐,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一匣砖、第九天 我趴在偏房一處隱蔽的房頂上張望科吭。 院中可真熱鬧,春花似錦猴鲫、人聲如沸对人。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牺弄。三九已至,卻和暖如春宜狐,著一層夾襖步出監(jiān)牢的瞬間势告,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工抚恒, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留咱台,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓俭驮,卻偏偏與公主長得像回溺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子混萝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容