Android跳转到第三方app,运行时长监听

1. 问题描述

需要实现从我们app跳转到第三方app,并统计第三方app在前台所待时长的功能。

2. 问题分析

大概过程如下:
1)首先得有权限,我们这个需要实现允许查看应用使用情况悬浮窗两个权限。
2)跳转到第三方app;
3)启动一个服务监听;
4)弹出一个悬浮窗
5)监听第三方app是否在前台运行。实现思路是启动一个定时器,每隔1s去查看前台应用信息。
6)预期时间完成,销毁悬浮窗,解绑Service。

3. 实现过程

3.1 悬浮窗
  • 悬浮窗权限
    当我们自己app在后台运行时,无法弹出一个Toast或者Dialog,所以得做一个类似于360安全卫士一样的悬浮窗。所以得要申请悬浮窗权限。6.0之前只需要在AndroidManifest文件中申请:
    1
    2
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>

6.0之后,代码中动态申请,需要跳转到系统设置中去获取:

1
2
3
4
5
6
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if (!Settings.canDrawOverlays(MainActivity.this)){
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUESTCODE_OVER);
}
}
  • 显示一个悬浮窗
    显示一个悬浮窗,首先写一个布局文件,然后添加到WindowManager中。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // LayoutInflater.from中Context用getApplicationContext()
    View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.layout_window,null);
    WindowManager mWindowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);
    WindowManager.LayoutParams params = new WindowManager.LayoutParams();
    //设置type.系统提示型窗口,一般都在应用程序窗口之上.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
    params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
    }else{
    params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
    }
    //设置效果为背景透明.
    params.format = PixelFormat.RGBA_8888;
    //设置flags.不可聚焦及不可使用按钮对悬浮窗进行操控.
    params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

    //设置窗口初始停靠位置.
    params.gravity = Gravity.LEFT | Gravity.TOP;
    params.x = 0;
    params.y = 0;

    params.width = WindowManager.LayoutParams.MATCH_PARENT;
    params.height = WindowManager.LayoutParams.WRAP_CONTENT;

    mWindowManager.addView(view,params);
  • 注意: 在Android 8.0后 params.type变化。具体参考: Android 8.0 悬浮窗变动与用法
3.2 监听app在前台运行

Android检测app运行在前台,5.0以前是通过获取手机当前活跃进程列表,5.0后这种办法用不了了,5.0以后通过UsageStatsManager(统计服务类)来获取。

1)5.0之前

通过ActivityManager获取运行app进程来判断app是否处于前台。

1
2
3
4
5
6
7
8
9
10
11
12
13
public boolean isRunningForeground(Context context,String packageName){
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> processes = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo processInfo: processes) {

if (processInfo.processName.equals(context.getPackageName())) {
if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return true;
}
}
}
return false;
}
2)5.0之后

Android5.0之后通过UsageStatsManager(统计服务类)

  • 申请“允许查看应用使用情况”。

5.0以后查看应用使用情况

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

在代码中,我们也做一层判断,是否已经获取该权限,如果没有,则跳转到设置权限界面:

1
2
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivityForResult(intent,REQUESTCODE_USAGE);
  • 获取最近运行app
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public String getRunningPackageNameOver21(Context context){
    String topPackageName = "";
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
    return topPackageName;
    }
    // 1.获取统计服务类
    UsageStatsManager usageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
    long currTime = System.currentTimeMillis();
    //2.获取从今天0点到现在的使用情况
    List<UsageStats> usageStatsList = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, getStartTime(),currTime);
    //3.根据最后使用时间降序排列
    Collections.sort(usageStatsList,new UsageComparator());

    //获取前台应用,排除其他应用因通知栏而产生的统计信息
    Field mLastEventField = null;
    try {
    mLastEventField = UsageStats.class.getField("mLastEvent");
    } catch (NoSuchFieldException e) {
    e.printStackTrace();
    }
    for (UsageStats usageStats:usageStatsList){
    if (mLastEventField != null){
    int lastEvent = 0;
    try {
    lastEvent = mLastEventField.getInt(usageStats);
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    }

    if (lastEvent == 1){
    topPackageName = usageStats.getPackageName();
    // Log.i(TAG,"包名:" + usageStats.getPackageName() + ",:" + dateFormat.format(new Date(date)));
    return topPackageName;
    }
    }
    }
    return topPackageName;
    }

    4. 最后效果

源码:https://github.com/AnXy1218/AppRunTime

实现list的深拷贝 Android跳转到第三方app,运行时长监听
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×