1. 程式人生 > >Android獲取前臺程序技術方案

Android獲取前臺程序技術方案

Andoid系統從Android5.0開始對獲取前臺程序介面進行相關限制。本文為對突破Android介面限制進行的一系列研究的總結。目前所有獲取前臺程序的介面有如下7種方式:

接下來將對每一種方案進行詳細的闡述。

1.通過RunningTask

1.1.實現原理

當一個App處於前臺的時候,會處於RunningTask的這個棧的棧頂,所以我們可以取出RunningTask的棧頂的任務程序,看他與我們的想要判斷的App的包名是否相同,來達到效果。

程式碼實現如下:

1.2.方案缺點

getRunningTask方法在Android5.0以上已經被廢棄,只會返回自己和系統的一些不敏感的

task,不再返回其他應用的task,用此方法來判斷自身App是否處於後臺,仍然是有效的,但是無法判斷其他應用是否位於前臺,因為不再能獲取資訊

2.通過RunningProcess

2.1.實現原理

通過runningProcess獲取到一個當前正在執行的程序的List,我們遍歷這個List中的每一個程序,判斷這個程序的一個importance 屬性是否是前臺程序,並且包名是否與我們判斷的APP的包名一樣,如果這兩個條件都符合,那麼這個App就處於前臺。

程式碼實現如下:

2.2.方案缺點

1、對於前臺Service(通過setForeground介面設定)的程序會被誤判判斷是前臺程序,程式碼上的表現就是

appProcess.importance的值永遠是ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND,這樣就會存在誤判的情況出現。

2、該方案只在Android5.0之前有效,Android5.0以後也被系統廢棄。而且基於Android5.0的小米開發版及部分基於Android5.0的華為版本該方案也會存在問題。

針對會在部分Android5.0的機型上存在問題的問題,我封裝了一個測試介面用於判斷,如果該介面返回為true則說明為問題機型,則RunningProcess方案不適用。測試介面的思想為:先通過getRunningAppProcesses

獲取到程序的List,然後判斷如果程序數量非常少(這裡設定的閾值為3個),或者程序列表中只有Launcher和應用自身存在,則認為介面存在問題。測試程式碼如下:

3.通過ActivityLifecycleCallbacks

3.1.實現原理

AndroidSDK14Application類裡增加了ActivityLifecycleCallbacks,我們可以通過這個Callback拿到App所有Activity的生命週期回撥。

public interface ActivityLifecycleCallbacks {

voidonActivityCreated(Activity activity, Bundle savedInstanceState);

voidonActivityStarted(Activity activity);

voidonActivityResumed(Activity activity);

voidonActivityPaused(Activity activity);

voidonActivityStopped(Activity activity);

voidonActivitySaveInstanceState(Activity activity, Bundle outState);

voidonActivityDestroyed(Activity activity);

    }

知道這些資訊,我們就可以用更官方的辦法來解決問題,當然還是利用方案二里的Activity生命週期的特性,我們只需要在ApplicationonCreate()裡去註冊上述介面,然後由Activity回調回來執行狀態即可。

3.2.方案特點

1、Android應用開發中一般認為back鍵是可以捕獲的,而Home鍵是不能捕獲的(除非修改framework,雖然這兩種方式的Activity生命週期並不相同,但是二者都會執行onStop();所以並不關心到底是觸發了哪個鍵切入後臺的。另外,Application是否被銷燬,都不會影響判斷的正確性。

2、該方案除了用於判斷當前應用內那個Activity位於前臺外,還可以用於作為實現“程序完全退出”的一種很好的技術方案。

3、該方案需要在Application中進行註冊相關Activity生命週期的回撥,主要程式碼如下:

在用該介面判斷應用是否在前臺時,只需要對activityCount計數進行判斷即可:

4.通過UsageStatsManager獲取

4.1.實現原理

通過使用UsageStatsManager獲取,此方法是Android5.0之後提供的新API,可以獲取一個時間段內的應用統計資訊,但是必須滿足一下要求

使用前提

1、此方法只在android5.0以上有效

2AndroidManifest中加入此許可權

3、手動開啟許可權:開啟手機設定,點選安全-高階,在有權檢視使用情況的應用中,為這個App打上勾

該方案的實現程式碼如下:

4.2.方案特點

1、該方案最大的缺點是需要使用者手動授權,因此在使用時要結合場景做適當引導。

2、該方案為Android5.0以後Google官方比較推薦的獲取程序資訊的方式,是最符合Google意圖的方式,不過在使用時會有一些延時需要小心處理。

4.3.相關輔助介面

1、跳轉到檢視應用使用許可權介面的跳轉程式碼如下:

2、判斷檢視應用使用許可權是否開啟的介面:

5.通過AccessibilityService獲取

5.1.技術原理

Android 輔助功能(AccessibilityService) 為我們提供了一系列的事件回撥,幫助我們指示一些使用者介面的狀態變化。我們可以派生輔助功能類,進而對不同的AccessibilityEvent進行處理。同樣的,這個服務就可以用來判斷當前的前臺應用

5.2.方案特點

1. AccessibilityService有非常廣泛的 ROM 覆蓋,特別是非國產手機,從 API Level 8(Android 2.2) API Level 23(Android 6.0)

2. AccessibilityService不再需要輪詢的判斷當前的應用是不是在前臺,系統會在視窗狀態發生變化的時候主動回撥,耗時和資源消耗都極小。

3. 不需要許可權請求

4. 它是一個穩定的方法,並非利用 Android 一些設計上的漏洞,可以長期使用的可能很大。

5. 可以用來判斷任意應用甚至 ActivityPopupWindow Dialog 物件是否處於前臺。

5.3.方案缺點

1、需要使用者手動開啟輔助功能。

2、輔助功能會伴隨應用被“強行停止”或第三方管理工具通過Root而剝奪,而且程序重啟後需要對使用者進行重新引導開啟。

3、部分廠商可能對輔助功能進行限制,如已發現的vivo的部分機型

5.4.方案實現

1、派生 ACCESSIBILITY SERVICE,建立視窗狀態探測服務:

4、建立 ACCESSIBILITY SERVICE INFO 屬性檔案:

5、AndroidManifes.xml中註冊第1步定義的Service

6、使用服務判斷應用是否在前臺:

5.5.相關輔助介面

1、跳轉到“輔助功能”設定介面的程式碼如下:

2、判斷輔助功能是否開啟的程式碼如下:

6.自解析/process獲取

6.1.技術原理

Linux系統核心會把process程序資訊儲存在/proc目錄下,通過JNI封裝介面,在JNI中去訪問並解析相關程序的裝置節點,再根據程序的屬性判斷是否為前臺

6.2.方案特點

1、不需要任何許可權。

2、可以判斷任意一個應用是否在前臺,而不侷限在自身應用。

3、當/proc下資料夾過多時,此方法是耗時操作。

4、該方案存在能耗問題。

5、在Android6.0.1以上版本或部分廠商版本受限於SEAndroid,只能獲取到第三方程序的資訊。

6.3.程式碼實現

Android層我們平時使用較多的程序屬性包括:piduidprocessNamepackageNameimportance等,在自解析方案中只對這些屬性進行解析就可以滿足大部分需求。

該方案中需要進行解析的裝置節點包括:

6.4.程式碼缺點

1、該方案在6.0手機適配執行OK,但在最新的小米、華為6.0.1手機中發現受SELinux的限制,無法讀取系統應用的裝置節點進行解析,只能解析第三方應用裝置節點。

2、可能存在能耗問題。

6.5.能耗問題解決

1、Java層物件快取:對呼叫比較頻繁的Java層物件在JNI中建立全域性快取,這就避免了每次呼叫時都需要通過JNI介面獲取。

對一些判斷是需要的場景在初始化時有Java層傳入Jni層,並建立全域性快取:

2、過來為Android程序:將pid小於1000Native程序過濾掉。

3、只解析發生變化的程序:在每次輪詢解析/proc節點時先判斷程序的pid在快取中是否存在,如果存在只需要更新程序的優先順序資訊,其他資訊不會發生變化;如果程序之前不存在則需要全新解析:

命中快取時的解析程式碼如下:

未命中快取時,則進全新解析:

4、在解析程序時,過來父程序為zygote的程序:Android中所有應用程序的父程序都是zyote

5、Java層對呼叫做快取處理:對於呼叫比較頻繁的情況,如果當次Native呼叫沒有完成,則之前返回之前的值,不需要堵塞等待。

6、對於只關心前臺程序的場景進行特殊處理:

通過優化後,適配方案的能耗與系統介面基本保持一致:

7.作為系統程序的獲取方式

相關推薦

Android獲取前臺程序技術方案

Andoid系統從Android5.0開始對獲取前臺程序介面進行相關限制。本文為對突破Android介面限制進行的一系列研究的總結。目前所有獲取前臺程序的介面有如下7種方式: 接下來將對每一種方案進行詳細的闡述。 1.通過RunningTask 1.1.實現原理

Android之IPC程序通訊方案適用場景總結

IPC是 Inter-Proscess Communication的縮寫,含義為程序間的通訊或者跨程序通訊,是指兩個程序之間進行資料交換的過程。 名稱 優點 缺點 適用場景 Bundle 簡單易用 只能傳輸Bundle支援的資料型別 四大元件間的

Android & IOS視訊錄製技術方案

轉載文章請註明出處:http://write.blog.csdn.net/postedit/48104617 移動端視訊錄製的技術方案,我所能想到並且嘗試過的,有如下幾種:方案一: 用系統開發sdk錄製的介面。 弊端:  1):不能更改視訊比例,一般都有該手機螢幕解析度所對應得視訊錄製解析度,另外手機系統提

Android APK加殼技術方案【2】

本文章由Jack_Jia編寫,轉載請註明出處。   一、序言         在上篇“Android APK加殼技術方案”(http://blog.csdn.net/jiazhijun/article/details/8678399)博文中,根據加殼資料在解殼程式D

[技術分享]20171212_後端開發_批量刪除使用@requestBody註解獲取前臺傳遞參數

項目 quest seq cli 如果 上一個 整理 delete pos 批量刪除 難點在於前臺的參數如何組織?組織完的參數後臺如何接收? 我現在就把我們項目中用到的批量刪除的方法整理出來,供大家參考。 先上一個通用版: var ids = new Array(); v

Android獲取裝置唯一標識解決方案

關於Android裝置唯一識別符號號 前言 由於在開發中需要開發遊客模式,在使用者沒有登入的情況下必須確保裝置的唯一性,於是慣性思維想到的肯定是使用DevicesId 來作為裝置的唯一標識,用以代替使用者登入以後的唯一識別符號。 但是由於國內複雜的rom定製情況,以及使

Android獲取應用程式名稱的穩定、可靠、簡單方案

獲取Android應用程式名稱的穩定、可靠、簡單方案 在Android開發中,相信絕大多數Android開發者使用的是網路上盛傳的這個方法獲取應用程式名稱的: /*** * 獲取應用程式名稱。 * @param context * @

android 判斷App程序是否存在,處在前臺,後臺,前後臺切換,service是否執行,設定為系統app

1.判斷程序是否存在 //判斷是否在主程序,這個方法判斷程序名或者pid都可以,如果程序名一樣那pid肯定也一樣 //true:當前程序是主程序 false:當前程序不是主程序 public boolean isUIProcess() { ActivityManager

android 獲取視訊縮圖終極解決方案(ffmpeg)

前些天有個師弟(在做一個仿LinkInEyes行車記錄儀的app)問我怎麼獲取視訊縮圖,起初以為很簡單,就找了個常用的解決方案(使用者獲取正常的視訊檔案的縮圖): 方案1: private void initView() { imgPic = (

android獲取裝置唯一標識完美解決方案

這是Android系統為開發者提供的用於標識手機裝置的串號,也是各種方法中普適性較高的,可以說幾乎所有的裝置都可以返回這個串號,並且唯一性良好。 這個DEVICE_ID可以同通過下面的方法獲取: TelephonyManager tm = (TelephonyManager)getSystemServi

android獲取裝置唯一標識完美解決方案的思考以及實現方式

前言 由於在開發中需要開發遊客模式,在使用者沒有登入的情況下必須確保裝置的唯一性,於是慣性思維想到的肯定是使用DevicesId 來作為裝置的唯一標識,用以代替使用者登入以後的唯一識別符號。 但是由於國內複雜的rom定製情況,以及使用者許可權禁止的情況。De

Android 獲取視訊(本地和網路)縮圖的解決方案

在Android 開發視訊的時候,通常都需要顯示視訊列表,而視訊列表通常都有一張視訊縮圖,那麼它是怎麼獲取的呢, 關於網路視訊的縮圖的實現方案主要有兩種: 1、後臺返回視訊時順便連縮圖的路徑都返回給你了,這樣前端壓力輕鬆。 2、後臺是返回視訊路徑,關於縮圖

關於Android獲取流量計數TrafficStats.getUidRxBytes(uid)和TrafficStats.getUidTxBytes(uid)返回-1解決方案

最近一個關於流量的專案在Android7.0系統的手機上執行,一直獲取不到流量的使用資料,檢視原始碼然後發現TrafficStats.getUidRxBytes(uid)和TrafficStats.

Android Dex 分包+熱修復(QQ空間技術方案

import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException;

android 獲取程序名字

1、獲取程序ID: android.os.Process.myPid() 2、通過程序id 獲取程序名字 public static String getAppNameByPID(Context context, int pid){ ActivityMan

android獲取程序資訊,執行記憶體資訊

public static List<TaskInfo> getTaskInfos(Context context) { //首先獲取到程序管理器 Act

如何讓Android service程序變成前臺程序

Android的前臺Service        Service幾乎都是在後臺執行的,一直以來它都是默默地做著辛苦的工作。但是Service的系統優先順序還是比較低的,當系統出現記憶體不足情況時,就有可能會回收掉正在後臺執行的Service。如果你希望Service可以一直

android 摘要----資料儲存全方案,詳解持久化技術

資料持久化:         只將那些記憶體中的瞬時資料儲存到儲存裝置中,保證即使在手機或電腦關機的情況下,這些資料也不會丟失。 1,檔案儲存:             是android中最基本的一種資料儲存方式,不對儲存內容進行任何格式化處理,所有詩句原封不動的儲存到檔案

Android 殺掉當前程序的進程

當前 logs android 我們 ces roi strong 退出 tro 在銷毀所有活動的代碼後面再加上殺掉當前進程的代碼,以保證程序完全退出,殺掉進程的代碼如下所示: android.os.Process.killProcess(android.os.Proce

Android獲取日期及星期的方法

ext text () oid get erro pre 公歷 format Calendar calendar=Calendar.getInstance(); SimpleDateFormat simpleDateFormat=new SimpleDateFormat("