【Demo 记录】获取栈顶APP所在的应用包名 --getRunningTasks 弃用的处理方案

–分两种情况处理,
低于5.0:使用getRunningTasks
高于5.0:使用,PACKAGE_USAGE_STATE 查看使用情况的这个权限
这个权限,只能系统app使用,要使用,需要在该权限后面添加上忽略,并且在用户使用时,给用户自己来打开app的查看使用情况的权利。这个权限不属于6.0权限,使用其他方式动态申请该权限无效。

使用场景
定时打印app的栈顶app 所在的包名称

Demo场景实例
创建一个服务,服务里面设置一个定时器,每隔5s打印一次栈顶app所在的包名,在布局文件中,设置一个按钮,用于打开这个服务。


1、添加权限

<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission
    android:name="android.permission.PACKAGE_USAGE_STATS"
    tools:ignore="ProtectedPermissions" />

2、服务的设置

注意: 服务 需要在清单文件中进行注册

/**
 * 自定义服务  时刻记录手机的栈顶activity 所在包
 */
public class TopAppService extends Service {
    private Timer timer;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("TopAppService", "服务执行了");
        if (timer == null) {
            timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    //判断是否有use 查看使用情况的权限
                    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                        boolean useGranted = isUseGranted();
                        Log.e("TopAppService", "use 权限 是否允许授权=" + useGranted);
                        if (useGranted) {
                            String topApp = getHigherPackageName();
                            Log.e("TopAppService", "顶层app=" + topApp);
                        } else {
                            //开启应用授权界面
                            Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }
                    } else {
                        String topApp = getLowerVersionPackageName();
                        Log.e("TopAppService", "顶层app=" + topApp);
                    }
                }
            }, 0, 5000);//每隔5s 执行一次
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 判断  用户查看使用情况的权利是否给予app
     *
     * @return
     */
    private boolean isUseGranted() {
        Context appContext = MyApplication.getAppContext();
        AppOpsManager appOps = (AppOpsManager) appContext
                .getSystemService(Context.APP_OPS_SERVICE);
        int mode = -1;
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
            mode = appOps.checkOpNoThrow("android:get_usage_stats",
                    android.os.Process.myUid(), appContext.getPackageName());
        }
        boolean granted = mode == AppOpsManager.MODE_ALLOWED;
        return granted;
    }

    /**
     * 高版本:获取顶层的activity的包名
     *
     * @return
     */
    private String getHigherPackageName() {
        String topPackageName = "";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
            long time = System.currentTimeMillis();
            //time - 1000 * 1000, time 开始时间和结束时间的设置,在这个时间范围内 获取栈顶Activity 有效
            List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time);
            // Sort the stats by the last time used
            if (stats != null) {
                SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
                for (UsageStats usageStats : stats) {
                    mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
                }
                if (mySortedMap != null && !mySortedMap.isEmpty()) {
                    topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
                    Log.e("TopPackage Name", topPackageName);
                }
            }
        } else {
            ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            ComponentName topActivity = activityManager.getRunningTasks(1).get(0).topActivity;
            topPackageName = topActivity.getPackageName();
        }
        return topPackageName;
    }

    /**
     * 低版本:获取栈顶app的包名
     *
     * @return
     */
    private String getLowerVersionPackageName() {
        String topPackageName;//低版本  直接获取getRunningTasks
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        ComponentName topActivity = activityManager.getRunningTasks(1).get(0).topActivity;
        topPackageName = topActivity.getPackageName();
        return topPackageName;
    }
}

获取高版本栈顶app所在的包名,方案来自于网络,这里只是个人记录解决方案。


ps,此处有问题

打算优化一下代码,整理下代码,就将获取栈顶app的高版本方式和低版本方式整合为一个方法了,最后竟然报错了,编译不通过

Error:Execution failed for task ':app:transformClassesWithInstantRunForDebug'.
> java.lang.ClassNotFoundException: android.app.usage.UsageStatsManager

说是找不到这个类,照上面的方式编译却能通过,在修改过程中,我也没有修改逻辑,为什么上面的方式就能够通过,我整合在一起写就有问题了呢?

—网上百度这个错误,也没找到合理的说话,任然存在疑惑。

猜测:和编译器有关,编译器对当前项目的编译,会将与将该版本下的相关的方法都进行编译,该版本下要调用哪个方法,那个方法就会被编译。

创建两个方法(高版本和低版本)时:在低版本上面执行,由于是直接调用的获取低版本的方法,高版本的方法不会被编译。
如果将两个方法整合到一起,那么在低版本上面执行时,调用这个方法之后,这个方法就要被编译,而高版本的相关类在低版本上是不存在的。所以就报了上面的错。


3、通过按钮 开启服务

Intent intent = new Intent(this, TopAppService.class);
startService(intent);

4、运行效果

模拟器(版本号17) 运行效果—低版本

这里写图片描述

手机(乐视2 android6.0)运行效果—高版本
在手机上,没有查看使用情况权利时跳转到授权界面

这里写图片描述
这里我已经将GetTopActivity 的权限开启了。

手机上执行时的log信息:

这里写图片描述

5、主要demo文件下载地址

主要涉及:
MainActivity.java
MyApplication.java
TopAppService.java
AndroidManifest.xml
http://download.csdn.net/detail/u012391876/9716756

猜你喜欢

转载自blog.csdn.net/u012391876/article/details/53765399
今日推荐