android5.0之后如何获取当前运行的应用包名

最近在项目中需要在用户处于某一个指定的应用(非当前项目的应用)界面时,自动弹出提示窗口。为了判断触发时机,我们需要判断当前前台应用的包名,那么如何获取前台应用的包名呢?

一种很自然的思路是获取当前运行栈中栈顶的activity,然后获取该activity的包名,最后进行判断,于是有了下面的代码——

public static String getTopActivity(Context context) {
		try {
			ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
			//获取正在运行的task列表,其中1表示最近运行的task,通过该数字限制列表中task数目,最近运行的靠前
			List runningTaskInfos = manager.getRunningTasks(1);

			if (runningTaskInfos != null && runningTaskInfos.size() != 0) {
				return (runningTaskInfos.get(0).baseActivity).getPackageName();
			}
		} catch (Exception e) {
			logger.error("栈顶应用:" + e);
		}
		return "";
	}
这种方式在android5.0之前是没有问题的,然而,Android 5.0开始,Google开始对getRunningTasks接口进行限制使用。之前,使用该接口需要 android.permission.GET_TASKS即使是自己开发的普通应用,只要声明该权限,即可以使用getRunningTasks接口。但从5.0开始,这种方式以及废弃。

应用要使用该接口必须声明权限android.permission.REAL_GET_TASKS而这个权限是不对三方应用开放的。(在Manifest里申请了也没有作用),系统应用(有系统签名)可以调用该权限。

于是,有了另外一种思路:即运行应用的进程名称默认为包名,那么是不是可以通过获取进程信息间接获取到前台运行应用的包名呢?

public static String getLollipopRecentTask(Context context) {
		final int PROCESS_STATE_TOP = 2;
		try {
			//通过反射获取私有成员变量processState,稍后需要判断该变量的值
			Field processStateField = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
			List processes = ((ActivityManager) context.getSystemService(
					Context.ACTIVITY_SERVICE)).getRunningAppProcesses();
			for (ActivityManager.RunningAppProcessInfo process : processes) {
				//判断进程是否为前台进程
				if (process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
					int state = processStateField.getInt(process);
					//processState值为2
					if (state == PROCESS_STATE_TOP) {
						String[] packname = process.pkgList;
						return packname[0];
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}
但是该方法的前提是前台Activity所在进程的名称为包名,若在manifest中自定义了其他的进程名,则失效。

以上。


你可能感兴趣的:(android之旅1.0)