( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)🥬( ´◔︎ ‸◔︎)
借助ActivityManager独特的属性,根据进程重要性来判断当前APP的前后台状态,一般在前台进程为IMPORTANCE_FOREGROUND,请注意,这只是一般的情况,如果某一个Service设置为sticky,那么会将这个进程的重要性进行提升,至于提升到IMPORTANCE_FOREGROUND_SERVICE还是 IMPORTANCE_FOREGROUND,博主还没有实质性验证,从之前阅读资料来看,即使在Android11后增加IMPORTANCE_FOREGROUND_SERVICE,但是更多使用的依旧是 IMPORTANCE_FOREGROUND。
public class AppUtils {
public static Boolean isAppInBackground(Context context){
ArrayList<Integer> list = getProcessImportance(context);
if (list != null && list.size() > 0) {
for (Integer importance : list) {
if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return false;
}
}
}
return true;
}
private static ArrayList<Integer> getProcessImportance(Context context){
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager == null) {
Log.d("AppUtils", "getProcessImportance: activityManager is null");
return null;
}
ArrayList<Integer> list = new ArrayList<>();
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfos = activityManager.getRunningAppProcesses();
if (runningAppProcessInfos != null && runningAppProcessInfos.size() > 0) {
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcessInfos) {
if (runningAppProcessInfo.processName.equals(context.getPackageName())) {
list.add(runningAppProcessInfo.importance);
Log.d("AppUtils",
"getProcessImportance: importanceReasonCode=" + runningAppProcessInfo.importanceReasonCode
+ ", importanceReasonComponent=" + runningAppProcessInfo.importanceReasonComponent);
}
}
}
Log.d("AppUtils", "getProcessImportance: " + list);
return list;
}
}
虽然方法可以用,但是官方还是在getRunningAppProcesses中注释道:
Note: this method is only intended for debugging or building a user-facing process management UI.
这是有一些考虑的,例如通过getRunningAppProcesses能获取的信息可能会包含敏感数据(如当前正在运行的应用列表,具体来看,在Android6以下版本可以获取到其他正在运行的app的信息,但是在Android6及以上版本中已经做了限制,如何限制的:
@GuardedBy("mService")
List<ActivityManager.RunningAppProcessInfo> getRunningAppProcessesLocked(boolean allUsers,
int userId, boolean allUids, int callingUid, int clientTargetSdk) {
// Lazy instantiation of list
List<ActivityManager.RunningAppProcessInfo> runList = null;
//非自己的uid就直接跳过了
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if ((!allUsers && app.userId != userId)
|| (!allUids && app.uid != callingUid)) {
continue;
}
。。。省略一些代码。。。
}
return runList;
}
那么getRunningAppProcesses既然被质疑有风险了,如何规避呢?其实方法很多,不仅可以通过反射ActivityThread,也可以通过IO直接命令拿到,下面附一种替换方法:
private static String replaceMethod() {
BufferedReader reader = null;
try {
FileInputStream inputStream = new FileInputStream(FILE_SYSTEM + android.os.Process.myPid() + BASE_FILE);
reader = new BufferedReader(new InputStreamReader(inputStream, CHARSET));
int c;
StringBuilder processName = new StringBuilder();
while ((c = reader.read()) > 0) {
processName.append((char) c);
}
return processName.toString();
} catch (Throwable e) {
Log.e(TAG, e.getLocalizedMessage());
} finally {
//别忘了关闭呦
if (reader != null) {
try {
reader.close();
} catch (Throwable e) {
Log.e(TAG, e.getLocalizedMessage());
}
}
}
return null;
}
本次方法介绍到此就结束啦,续集请看juejin.cn/post/732159…