Android 必知必會 - 根據包名判斷 App 執行狀態

cafeting發表於2017-02-07

獲取指定包名的 APP 是否還在後臺執行,判斷 APP 是否存活。

背景

可以根據 App 是否有 Service 分兩類情況處理:

  • 沒有 Service
  • Service

對於沒有 Service 的 App,程式一旦切換到後臺,可能很快就被回收了,這裡使用 ActivityManager.getRunningTasks(int maxNum) 方法來獲取當前正在執行的任務,注意:此方法並不被系統推薦,且是一個 Deprecated 的方法。

對於有 Service 的 App,大多會有多個 Service ,且有可能都是 :remote 型別的,這樣在判斷上需要進行一定的處理,這裡根據 App 的 uid 來判斷,避免在一些特殊的情況下判斷存活不準確的問題。我們使用 ActivityManager.getRunningServices(int maxNum) 方法獲取當前執行中的 Service 列表。

注意:App 的 uid 對於系統內建 App 而言不是唯一的,Android 內建的應用會有共用 uid 的情況。如果你是開發系統內建應用或者類似的東西,務必要自行進行特殊方式檢查。

實現

下面是幾個工具類,在正式使用的時候需要配合使用,才能覆蓋全部情況:

    /**
     * 方法描述:判斷某一應用是否正在執行
     * Created by cafeting on 2017/2/4.
     * @param context     上下文
     * @param packageName 應用的包名
     * @return true 表示正在執行,false 表示沒有執行
     */
    public static boolean isAppRunning(Context context, String packageName) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(100);
        if (list.size() <= 0) {
            return false;
        }
        for (ActivityManager.RunningTaskInfo info : list) {
            if (info.baseActivity.getPackageName().equals(packageName)) {
                return true;
            }
        }
        return false;
    }


    //獲取已安裝應用的 uid,-1 表示未安裝此應用或程式異常
    public static int getPackageUid(Context context, String packageName) {
        try {
            ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(packageName, 0);
            if (applicationInfo != null) {
                Logger.d(applicationInfo.uid);
                return applicationInfo.uid;
            }
        } catch (Exception e) {
            return -1;
        }
        return -1;
    }

    /**
     * 判斷某一 uid 的程式是否有正在執行的程式,即是否存活
     * Created by cafeting on 2017/2/4.
     *
     * @param context     上下文
     * @param uid 已安裝應用的 uid
     * @return true 表示正在執行,false 表示沒有執行
     */
    public static boolean isProcessRunning(Context context, int uid) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> runningServiceInfos = am.getRunningServices(200);
        if (runningServiceInfos.size() > 0) {
            for (ActivityManager.RunningServiceInfo appProcess : runningServiceInfos){
                if (uid == appProcess.uid) {
                    return true;
                }
            }
        }
        return false;
    }複製程式碼

在正式使用的時候結合兩者即可:

String pName = "xxx";
int uid = getPackageUid(context, pName);
if(uid > 0){
      boolean rstA = isAppRunning(context, pName);
      boolean rstB = isProcessRunning(context, uid);
      if(rstA||rstB){
          //指定包名的程式正在執行中
      }else{
          //指定包名的程式未在執行中
      }
}else{
      //應用未安裝
}複製程式碼

總結

在探索驗證程式存活的過程中,發現 ActivityManager.RunningServiceInfo 包含很多資訊,一開始我是使用其 processstarted 屬性來判斷,其中 process 對應包名,但是對於只有 :remote 型別 service 時,則判定不了。

以上是最近開發中處理的一個需求,希望能對你有所幫助。如果你有更好的方法或者發現了文中的錯誤,可以通過下面的方式和我聯絡:

相關文章