判斷指定App是否位於前臺的方法

原文地址:http://p.codekk.com/detail/Android/wenmingvs/AndroidProcessjava

提供6種方法來判斷App處於前臺仍是後臺,而且封裝成工具類供你們使用linux

最後一種方法堪稱Android黑科技(非原創),既能夠突破Android5.0以上的權限封鎖,獲取任意前臺App的包名,又不須要權限,歡迎你們star個人新項目android

Download Linkgit

2016.2.11更新------感謝@EffectiveMatrix大神帶來的新的判斷先後臺的方法github

六種判斷方法展現

enter image description here

用法

傳入Context參數與想要判斷是否位於前臺的App的包名,會返回ture或者false表示App是否位於前臺安全

//六種方法任選其一

//使用方法一
Boolean isForeground = BackgroundUtil.getRunningTask(context, packageName);
//使用方法二
Boolean isForeground = BackgroundUtil.getRunningAppProcesses(context, packageName);
//使用方法三
Boolean isForeground = BackgroundUtil.getApplicationValue(context);
//使用方法四
Boolean isForeground = BackgroundUtil.queryUsageStats(context, packageName);
//使用方法五
Boolean isForeground = BackgroundUtil.getFromAccessibilityService(context, packageName);
//使用方法六
Boolean isForeground = BackgroundUtil.getLinuxCoreInfo(context, packageName);

六種方法的區別

方法 判斷原理 須要權限 能夠判斷其餘應用位於前臺 特色
方法一 RunningTask Android4.0系列能夠,5.0以上機器不行 5.0此方法被廢棄
方法二 RunningProcess 當App存在後臺常駐的Service時失效
方法三 ActivityLifecycleCallbacks 簡單有效,代碼最少
方法四 UsageStatsManager 須要用戶手動受權
方法五 經過Android無障礙功能實現 須要用戶手動受權
方法六 讀取/proc目錄下的信息 當proc目錄下文件夾過多時,過多的IO操做會引發耗時

方法一:經過RunningTask

enter image description here

原理
當一個App處於前臺的時候,會處於RunningTask的這個棧的棧頂,因此咱們能夠取出RunningTask的棧頂的任務進程,看他與咱們的想要判斷的App的包名是否相同,來達到效果服務器

缺點
getRunningTask方法在Android5.0以上已經被廢棄,只會返回本身和系統的一些不敏感的task,再也不返回其餘應用的task,用此方法來判斷自身App是否處於後臺,仍然是有效的,可是沒法判斷其餘應用是否位於前臺,由於再也不能獲取信息app

方法二:經過RunningProcess

enter image description here

原理
經過runningProcess獲取到一個當前正在運行的進程的List,咱們遍歷這個List中的每個進程,判斷這個進程的一個importance 屬性是不是前臺進程,而且包名是否與咱們判斷的APP的包名同樣,若是這兩個條件都符合,那麼這個App就處於前臺ide

缺點
在聊天類型的App中,經常須要常駐後臺來不間斷的獲取服務器的消息,這就須要咱們把Service設置成START_STICKY,kill 後會被重啓(等待5秒左右)來保證Service常駐後臺。若是Service設置了這個屬性,這個App的進程就會被判斷是前臺,代碼上的表現就是appProcess.importance的值永遠是 ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND,這樣就永遠沒法判斷出到底哪一個是前臺了。工具

方法三:經過ActivityLifecycleCallbacks

enter image description here

原理
AndroidSDK14在Application類裏增長了ActivityLifecycleCallbacks,咱們能夠經過這個Callback拿到App全部Activity的生命週期回調。

public interface ActivityLifecycleCallbacks {
        void onActivityCreated(Activity activity, Bundle savedInstanceState);
        void onActivityStarted(Activity activity);
        void onActivityResumed(Activity activity);
        void onActivityPaused(Activity activity);
        void onActivityStopped(Activity activity);
        void onActivitySaveInstanceState(Activity activity, Bundle outState);
        void onActivityDestroyed(Activity activity);
    }

知道這些信息,咱們就能夠用更官方的辦法來解決問題,固然仍是利用方案二里的Activity生命週期的特性,咱們只須要在Application的onCreate()裏去註冊上述接口,而後由Activity回調回來運行狀態便可。

可能還有人在糾結,我用back鍵切到後臺和用Home鍵切到後臺,同樣嗎?以上方法適用嗎?在Android應用開發中通常認爲back鍵是能夠捕獲的,而Home鍵是不能捕獲的(除非修改framework),可是上述方法從Activity生命週期着手解決問題,雖然這兩種方式的Activity生命週期並不相同,可是兩者都會執行onStop();因此並不關心究竟是觸發了哪一個鍵切入後臺的。另外,Application是否被銷燬,都不會影響判斷的正確性

方法四:經過使用UsageStatsManager獲取

enter image description here

原理
經過使用UsageStatsManager獲取,此方法是Android5.0以後提供的新API,能夠獲取一個時間段內的應用統計信息,可是必須知足一下要求

使用前提

  1. 此方法只在android5.0以上有效
  2. AndroidManifest中加入此權限
    <uses-permission xmlns:tools="http://schemas.android.com/tools" android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
  3. 打開手機設置,點擊安全-高級,在有權查看使用狀況的應用中,爲這個App打上勾

enter image description here

方法五:經過Android自帶的無障礙功能

很是感謝@EffectiveMatrix大神帶來的新的判斷先後臺的方法

此方法屬於他原創,具體的博文參照這裏http://effmx.com/articles/tong-guo-android-fu-zhu-gong-neng-accessibility-service-jian-ce-ren-yi-qian-tai-jie-mian/

此方法沒法直觀的經過下拉通知視圖來進行先後臺的觀察,請到LogCat中進行觀察便可,如下是LogCat中打印的信息

enter image description here

原理
Android 輔助功能(AccessibilityService) 爲咱們提供了一系列的事件回調,幫助咱們指示一些用戶界面的狀態變化。 咱們能夠派生輔助功能類,進而對不一樣的 AccessibilityEvent 進行處理。 一樣的,這個服務就能夠用來判斷當前的前臺應用

優點

  1. AccessibilityService 有很是普遍的 ROM 覆蓋,特別是非國產手機,從 Android API Level 8(Android 2.2) 到 Android Api Level 23(Android 6.0)
  2. AccessibilityService 再也不須要輪詢的判斷當前的應用是否是在前臺,系統會在窗口狀態發生變化的時候主動回調,耗時和資源消耗都極小
  3. 不須要權限請求
  4. 它是一個穩定的方法,與 「方法6」讀取 /proc 目錄不一樣,它並不是利用 Android 一些設計上的漏洞,能夠長期使用的可能很大
  5. 能夠用來判斷任意應用甚至 Activity, PopupWindow, Dialog 對象是否處於前臺

劣勢

  1. 須要要用戶開啓輔助功能
  2. 輔助功能會伴隨應用被「強行中止」而剝奪

方法六:讀取Linux系統內核保存在/proc目錄下的process進程信息

enter image description here

此方法並不是我原創,原做者是國外的大神,GitHub項目在這裏,https://github.com/jaredrummler/AndroidProcesses,也一併加入到工程中,供你們作全面的參考選擇

原理
無心中看到烏雲上有人提的一個漏洞,Linux系統內核會把process進程信息保存在/proc目錄下,Shell命令去獲取的他,再根據進程的屬性判斷是否爲前臺

優勢

  1. 不須要任何權限
  2. 能夠判斷任意一個應用是否在前臺,而不侷限在自身應用

缺點

  1. 當/proc下文件夾過多時,此方法是耗時操做

用法
獲取一系列正在運行的App的進程

List<AndroidAppProcess> processes = ProcessManager.getRunningAppProcesses();

獲取任一正在運行的App進程的詳細信息

AndroidAppProcess process = processes.get(location);
String processName = process.name;

Stat stat = process.stat();
int pid = stat.getPid();
int parentProcessId = stat.ppid();
long startTime = stat.stime();
int policy = stat.policy();
char state = stat.state();

Statm statm = process.statm();
long totalSizeOfProcess = statm.getSize();
long residentSetSize = statm.getResidentSetSize();

PackageInfo packageInfo = process.getPackageInfo(context, 0);
String appName = packageInfo.applicationInfo.loadLabel(pm).toString();

判斷是否在前臺

if (ProcessManager.isMyProcessInTheForeground()) {
  // do stuff
}

獲取一系列正在運行的App進程的詳細信息

List<ActivityManager.RunningAppProcessInfo> processes = ProcessManager.getRunningAppProcessInfo(ctx);