使用 NetworkStatsManager 获取移动数据使用历史 [英] Getting mobile data usage history using NetworkStatsManager

查看:38
本文介绍了使用 NetworkStatsManager 获取移动数据使用历史的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道数据使用历史并注意到新"android-6 NetworkStatsManager 这似乎是积极的(我已经使用 TrafficStats 一段时间了,但这不会涵盖重新启动之前的任何内容).

I want to know the data usage history and noticed the "new" android-6 NetworkStatsManager which seems positive (I've used TrafficStats a while but that won't cover anything previous a reboot).

来自 API 文档:

注意:此 API 需要 PACKAGE_USAGE_STATS 权限,这是一个系统级权限,不会授予第三方应用程序.但是,声明权限意味着有意使用 API 和设备的用户可以通过设置授予权限应用.个人资料所有者应用会自动获得权限查询有关他们管理的配置文件的数据(即,对于任何查询除了 querySummaryForDevice(int, String, long, long)).设备所有者应用同样可以访问主要用户的使用数据.

NOTE: This API requires the permission PACKAGE_USAGE_STATS, which is a system-level permission and will not be granted to third-party apps. However, declaring the permission implies intention to use the API and the user of the device can grant permission through the Settings application. Profile owner apps are automatically granted permission to query data on the profile they manage (that is, for any query except querySummaryForDevice(int, String, long, long)). Device owner apps likewise get access to usage data of the primary user.

我想知道汇总级别的数据使用情况,而不是具体到使用数据的应用程序,因此我尝试像这样使用它:

I want to know the data usage on a aggregated level and not down to which app that uses the data so I tried to use it like this:

NetworkStatsManager service = context.getSystemService(NetworkStatsManager.class);

NetworkStats.Bucket bucket = 
        service.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE, null, from, to);
...

不幸的是抛出了一个SecurityException:

java.lang.SecurityException: NetworkStats: Neither user 10174 nor current process has android.permission.READ_NETWORK_USAGE_HISTORY.
at android.os.Parcel.readException(Parcel.java:1620)
at android.os.Parcel.readException(Parcel.java:1573)
at android.net.INetworkStatsSession$Stub$Proxy.getDeviceSummaryForNetwork(INetworkStatsSession.java:259)
at android.app.usage.NetworkStats.getDeviceSummaryForNetwork(NetworkStats.java:316)
at android.app.usage.NetworkStatsManager.querySummaryForDevice(NetworkStatsManager.java:100)
...

android.permission.READ_NETWORK_USAGE_HISTORY 权限不允许用于第三方应用.所以这似乎是一个死胡同.

The android.permission.READ_NETWORK_USAGE_HISTORY permission is not allowed for third party apps. So this seemed like a dead end.

但是,我深入研究了内部结构,发现您可以使用内部/隐藏 API 来执行相同的操作,而无需请求任何权限:

However, I drilled down a bit into the internals and found out that you can use the internal/hidden API to do the same thing without requesting any permissions:

INetworkStatsService service =
        INetworkStatsService.Stub.asInterface(
                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));

INetworkStatsSession session = service.openSession();

NetworkTemplate mobileTemplate = NetworkTemplate.buildTemplateMobileWildcard();
int fields = NetworkStatsHistory.FIELD_RX_BYTES | NetworkStatsHistory.FIELD_TX_BYTES;

NetworkStatsHistory mobileHistory = session.getHistoryForNetwork(mobileTemplate, fields);

for (int i = 0; i < mobileHistory.size(); i++) {
    NetworkStatsHistory.Entry entry = mobileHistory.getValues(i, null);
    ...
}

session.close();

我真的很想对公共 API 做同样的事情,那么,我该怎么做?

I really want to do the same with the public API, so, how do I do just that?

推荐答案

有一种方法可以在不访问私有 API 的情况下获得对 NetworkStateManager 的访问权.以下是步骤:

There is way to obtain the access to NetworkStateManager without getting access to private API. Here are the steps:

  1. AndroidManifest.xml中声明所需的权限:

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

  1. Activity中请求许可

android.permission.PACKAGE_USAGE_STATS 不是普通权限,不能简单请求.为了检查是否已授予权限,请检查:

android.permission.PACKAGE_USAGE_STATS is not a normal permission, there cannot be simply requested. In order to check, whether the permission has been granted, check:

AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
        android.os.Process.myUid(), getPackageName());
if (mode == AppOpsManager.MODE_ALLOWED) {
    return true;
}

要请求此权限,只需调用 Intent:

To ask for this permission, simply call Intent:

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);

还需要另一个权限:Manifest.permission.READ_PHONE_STATE.仅当您需要获取 移动数据统计.但是,这是正常权限,因此可以请求为任何其他权限

Another permmission is also needed: Manifest.permission.READ_PHONE_STATE. It is needed only, when you need to get mobile data statistics. However, this is normal permission so can be requested as any other permission

  1. 使用NetworkStatsManager:

制作了一个示例 Github repo 来演示用法.

Made a sample Github repo demonstrating the usage.

这篇关于使用 NetworkStatsManager 获取移动数据使用历史的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆