从后台任务或服务中确定当前的前台应用程序

我希望有一个应用程序在后台运行,它知道什么时候内置的应用程序(消息传递,联系人等)正在运行。

所以我的问题是:

  1. 我应该如何在后台运行我的应用程序。

  2. 我的后台应用程序如何知道当前在前台运行的应用程序是什么。

来自有经验的人的反应将不胜感激。

关于“2.我的后台应用程序如何知道当前在前台运行的应用程序是什么。

不要使用getRunningAppProcesses()方法,因为这会从我的经验中返回各种系统垃圾,并且会得到多个包含RunningAppProcessInfo.IMPORTANCE_FOREGROUND结果。 使用getRunningTasks()来代替

这是我在我的服务中使用的代码来识别当前的前台应用程序,这非常简单:

 ActivityManager am = (ActivityManager) AppService.this.getSystemService(ACTIVITY_SERVICE); // The first in the list of RunningTasks is always the foreground task. RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); 

多数民众赞成它,那么你可以轻松地访问前台应用程序/活动的详细信息:

 String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName(); PackageManager pm = AppService.this.getPackageManager(); PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0); String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString(); 

这需要在活动清单中额外的许可,并且完美地工作。

 <uses-permission android:name="android.permission.GET_TASKS" /> 

我不得不艰难地找出正确的解决方案。 下面的代码是cyanogenmod7(平板调整)的一部分,并在Android 2.3.3 /姜饼上测试。

方法:

  • getForegroundApp – 返回前台应用程序。
  • getActivityForApp – 返回找到的应用程序的活动。
  • isStillActive – 确定之前发现的应用程序是否仍然是活动的应用程序。
  • isRunningService – getForegroundApp的帮助函数

这有希望在所有的范围内回答这个问题(:

 private RunningAppProcessInfo getForegroundApp() { RunningAppProcessInfo result=null, info=null; if(mActivityManager==null) mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); List <RunningAppProcessInfo> l = mActivityManager.getRunningAppProcesses(); Iterator <RunningAppProcessInfo> i = l.iterator(); while(i.hasNext()){ info = i.next(); if(info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && !isRunningService(info.processName)){ result=info; break; } } return result; } private ComponentName getActivityForApp(RunningAppProcessInfo target){ ComponentName result=null; ActivityManager.RunningTaskInfo info; if(target==null) return null; if(mActivityManager==null) mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); List <ActivityManager.RunningTaskInfo> l = mActivityManager.getRunningTasks(9999); Iterator <ActivityManager.RunningTaskInfo> i = l.iterator(); while(i.hasNext()){ info=i.next(); if(info.baseActivity.getPackageName().equals(target.processName)){ result=info.topActivity; break; } } return result; } private boolean isStillActive(RunningAppProcessInfo process, ComponentName activity) { // activity can be null in cases, where one app starts another. for example, astro // starting rock player when a move file was clicked. we dont have an activity then, // but the package exits as soon as back is hit. so we can ignore the activity // in this case if(process==null) return false; RunningAppProcessInfo currentFg=getForegroundApp(); ComponentName currentActivity=getActivityForApp(currentFg); if(currentFg!=null && currentFg.processName.equals(process.processName) && (activity==null || currentActivity.compareTo(activity)==0)) return true; Slog.i(TAG, "isStillActive returns false - CallerProcess: " + process.processName + " CurrentProcess: " + (currentFg==null ? "null" : currentFg.processName) + " CallerActivity:" + (activity==null ? "null" : activity.toString()) + " CurrentActivity: " + (currentActivity==null ? "null" : currentActivity.toString())); return false; } private boolean isRunningService(String processname){ if(processname==null || processname.isEmpty()) return false; RunningServiceInfo service; if(mActivityManager==null) mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); List <RunningServiceInfo> l = mActivityManager.getRunningServices(9999); Iterator <RunningServiceInfo> i = l.iterator(); while(i.hasNext()){ service = i.next(); if(service.process.equals(processname)) return true; } return false; } 

试试下面的代码:

 ActivityManager activityManager = (ActivityManager) newContext.getSystemService( Context.ACTIVITY_SERVICE ); List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); for(RunningAppProcessInfo appProcess : appProcesses){ if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){ Log.i("Foreground App", appProcess.processName); } } 

进程名称是在前台运行的应用程序的包名称。 将其与您的应用程序的软件包名称进行比较。 如果它是相同的,那么你的应用程序在前台运行。

我希望这回答了你的问题。

从棒棒糖开始,这变了。 请在下面的代码找到,然后用户必须去设置 – >安全 – >(向下滚动到最后)具有使用权限的应用程序 – >授予我们的应用程序的权限

 private void printForegroundTask() { String currentApp = "NULL"; if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE); long time = System.currentTimeMillis(); List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time); if (appList != null && appList.size() > 0) { SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>(); for (UsageStats usageStats : appList) { mySortedMap.put(usageStats.getLastTimeUsed(), usageStats); } if (mySortedMap != null && !mySortedMap.isEmpty()) { currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName(); } } } else { ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses(); currentApp = tasks.get(0).processName; } Log.e(TAG, "Current App in foreground is: " + currentApp); } 

ActivityManager类是查看哪些进程正在运行的适当工具。

要在后台运行,通常需要使用服务 。

为了确定前台应用程序,您可以使用它来检测前台应用程序,您可以使用https://github.com/ricvalerio/foregroundappchecker 。 它使用不同的方法取决于设备的Android版本。

至于服务,回购还提供你需要的代码。 本质上,让android studio为您创建服务,然后onCreate添加使用appChecker的片段。 但是,您需要请求权限。

考虑到getRunningTasks()被弃用和getRunningAppProcesses()不可靠,我来到一个解决方案,结合在StackOverflow中提到的两种方法:

  private boolean isAppInForeground(Context context) { if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName(); return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase()); } else { ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo(); ActivityManager.getMyMemoryState(appProcessInfo); if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE) { return true; } KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); // App is foreground, but screen is locked, so show notification return km.inKeyguardRestrictedInputMode(); } } 

做这样的事情:

 int showLimit = 20; /* Get all Tasks available (with limit set). */ ActivityManager mgr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> allTasks = mgr.getRunningTasks(showLimit); /* Loop through all tasks returned. */ for (ActivityManager.RunningTaskInfo aTask : allTasks) { Log.i("MyApp", "Task: " + aTask.baseActivity.getClassName()); if (aTask.baseActivity.getClassName().equals("com.android.email.activity.MessageList")) running=true; } 

这对我有效。 但它只给出主菜单名称。 也就是说,如果用户已经打开设置 – >蓝牙 – >设备名称屏幕,则RunningAppProcessInfo将其称为“设置”。 不能深入挖掘

 ActivityManager activityManager = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE ); PackageManager pm = context.getPackageManager(); List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); for(RunningAppProcessInfo appProcess : appProcesses) { if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(appProcess.processName, PackageManager.GET_META_DATA)); Log.i("Foreground App", "package: " + appProcess.processName + " App: " + c.toString()); } } 

在棒棒糖和以上:

添加到主要的:

 <uses-permission android:name="android.permission.GET_TASKS" /> 

做这样的事情:

 if( mTaskId < 0 ) { List<AppTask> tasks = mActivityManager.getAppTasks(); if( tasks.size() > 0 ) mTaskId = tasks.get( 0 ).getTaskInfo().id; } 

这是我如何检查我的应用程序是否在前台。 注意我正在使用官方Android文档建议的AsyncTask

`

  private class CheckIfForeground extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... voids) { ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { Log.i("Foreground App", appProcess.processName); if (mContext.getPackageName().equalsIgnoreCase(appProcess.processName)) { Log.i(Constants.TAG, "foreground true:" + appProcess.processName); foreground = true; // close_app(); } } } Log.d(Constants.TAG, "foreground value:" + foreground); if (foreground) { foreground = false; close_app(); Log.i(Constants.TAG, "Close App and start Activity:"); } else { //if not foreground close_app(); foreground = false; Log.i(Constants.TAG, "Close App"); } return null; } } 

并像这样执行AsyncTask。 new CheckIfForeground().execute();

我在一个方法中结合了两个解决方案,它适用于API 24和API 21.其他我没有测试。

Kotlin中的代码:

 private fun isAppInForeground(context: Context): Boolean { val appProcessInfo = ActivityManager.RunningAppProcessInfo() ActivityManager.getMyMemoryState(appProcessInfo) if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE) { return true } else if (appProcessInfo.importance == IMPORTANCE_TOP_SLEEPING || appProcessInfo.importance == IMPORTANCE_BACKGROUND) { return false } val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val foregroundTaskInfo = am.getRunningTasks(1)[0] val foregroundTaskPackageName = foregroundTaskInfo.topActivity.packageName return foregroundTaskPackageName.toLowerCase() == context.packageName.toLowerCase() } 

并在清单

 <!-- Check whether app in background or foreground --> <uses-permission android:name="android.permission.GET_TASKS" />