获取使用时长和点击次数

Android5.0之前,通过PkgUsageStats这个类可以统计到应用的使用情况,但这些类在SDK不公开。这里提供一种我们的解决方案,仅供参考:

sdk上级目录/sdk/platforms/android-19/data/layoutlib.jar

将layoutlib.jar使用User Library的方式(AndroidStudio可以使用Provided添加依赖),然后就可以使用这些类,下面给出具体实现:


// 获取使用时长
public static long getUseDuration(String pkgName) {

// 注意适配性问题,无法找到该类
try{
com.android.internal.app.IUsageStats mUsageStatsService = com.android.internal.app.IUsageStats.Stub
.asInterface(ServiceManager.getService("usagestats"));
PkgUsageStats[] stats;
try {
stats = mUsageStatsService.getAllPkgUsageStats();
} catch (Exception e) {
LogUtil.d("no permission get use duration");
e.printStackTrace();
return 0;
}
if (stats == null) {
return 0;
}

for (PkgUsageStats ps : stats) {
if (ps.packageName.equals(pkgName)) {
return ps.usageTime;
}
}
}catch(Exception e){

}
return 0;
}

 


// 获取使用次数
public static long getUseTime(String pkgName) {
// 注意适配性问题,无法找到该类
try{
com.android.internal.app.IUsageStats mUsageStatsService = com.android.internal.app.IUsageStats.Stub
.asInterface(ServiceManager.getService("usagestats"));
PkgUsageStats[] stats = null;
try {
stats = mUsageStatsService.getAllPkgUsageStats();
} catch (Exception e) {
LogUtil.d("no permission get use duration");
e.printStackTrace();
return 0;
}
if (stats == null) {
return 0;
}
for (PkgUsageStats ps : stats) {
if (ps.packageName.equals(pkgName)) {
return ps.launchCount;
}
}
}catch(Exception e){

}
return 0;
}
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
走一下IUsageStats 源码,从getAllPkgUsageStats()方法,将带到的信息保存到PkgUsageStats[]数组中并返回;

……省略代码
private static final java.lang.String DESCRIPTOR = "com.android.internal.app.IUsageStats";
……省略代码

private android.os.IBinder mRemote;
More ...Proxy(android.os.IBinder remote) {
mRemote = remote;
}

……省略代码

@Override
public com.android.internal.os.PkgUsageStats[] More ...getAllPkgUsageStats() throws android.os.RemoteException{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
com.android.internal.os.PkgUsageStats[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getAllPkgUsageStats, _data, _reply, 0);
_reply.readException();
//信息的数组
_result = _reply.createTypedArray(com.android.internal.os.PkgUsageStats.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
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
内部实现都是Parcel 和 Parcelable(之后补充这块知识),简单看一下createTypedArray()

public final <T> T[] More ...createTypedArray(Parcelable.Creator<T> c) {
int N = readInt();
if (N < 0) {
return null;
}
T[] l = c.newArray(N);
for (int i=0; i<N; i++) {
if (readInt() != 0) {
l[i] = c.createFromParcel(this);
}
}
return l;
}

//调用native方法
public final long More ...readInt() {
return nativeReadInt(mNativePtr);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
同流量一样,Linux 系统下所有的信息都是以文件的形式存在的,所以应用程序的使用信息也会被保存在操作系统的文件中,将信息从文件中读出,然后就将其用Parcelable序列化的过程;最后在看一下PkgUsageStats类源码:

public class More ...PkgUsageStats implements Parcelable {
//包名
public String packageName;
//启动次数
public int launchCount;
//使用时长
public long usageTime;
……省略大量代码
}
1
2
3
4
5
6
7
8
9
根据自身的业务逻辑,判断包名,获取每个应用的点击次数和使用时长;

以上只能保证写代码的时候不会出现错误提示,但是运行起来并不会带到想要的效果,还需要一下几步:

在应用程序的AndroidManifest.xml中的manifest节点中加入”android:sharedUserId=”android.uid.system”这个属性。
使用目标系统的platform密钥来重新给apk文件重新签名。
如果有相应的文件,使用如下批处理,a.apk表示你自己的apk,b.apk表示系统签名后生成的新apk

java -jar signapk.jar -w platform.x509.pem platform.pk8 a.apk b.apk

pause

之后将新生成的文件放到系统目录即可统计应用的使用次数和使用时长,具体情况视代码逻辑而定。

posted @ 2022-04-13 23:11  stdxxd  阅读(177)  评论(0)    收藏  举报