12

Desidero conoscere la cronologia di utilizzo dei dati e ho notato il "nuovo" android-6 NetworkStatsManager che sembra positivo (ho usato TrafficStats un po 'ma che non coprirà nulla di precedente un riavvio) .Ottenere la cronologia di utilizzo dei dati mobili utilizzando NetworkStatsManager

Dalla documentazione API:

NOTA: Questa API richiede i PACKAGE_USAGE_STATS autorizzazione, che è un permesso a livello di sistema e non sarà concesso per applicazioni di terze parti. Tuttavia, dichiarando che l'autorizzazione implica l'intenzione di utilizzare l'API e l'utente del dispositivo può concedere l'autorizzazione tramite l'applicazione Impostazioni . Alle app del proprietario del profilo viene automaticamente concessa l'autorizzazione per interrogare i dati sul profilo che gestiscono (ovvero, per qualsiasi query eccetto querySummaryForDevice (int, String, long, long)). Allo stesso modo, le applicazioni del proprietario del dispositivo ottengono l'accesso ai dati di utilizzo dell'utente principale.

voglio sapere l'uso di dati a livello aggregato e non giù a quale app che utilizza i dati così ho cercato di usare in questo modo:

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

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

Purtroppo che getta un 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) 
... 

Il android.permission.READ_NETWORK_USAGE_HISTORY permesso non è consentito per le applicazioni di terze parti. Quindi questo sembrava un vicolo cieco.

Tuttavia, ho forato giù un po 'nelle parti interne e ho scoperto che è possibile utilizzare l'API interna/nascosta per fare la stessa cosa senza richiedere alcun permesso:

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(); 

Ho molta voglia di fare lo stesso con l'API pubblica, quindi, come faccio?

+1

Ciao, sto cercando di fare la stessa cosa. Per questa autorizzazione: android.permission.READ_NETWORK_USAGE_HISTORY rimuovo l'avviso su manifest e l'app finalmente installata sul mio dispositivo. Ma quando provo ad ottenere TYPE_MOBILE restituisce sempre 0. WIFI funziona bene. Hai risolto questo problema? per favore fatemelo sapere :) –

+0

anche io mi trovo sempre 0 – aj0822ArpitJoshi

risposta

13

C'è un modo per ottenere l'accesso a NetworkStateManager senza ottenere l'accesso all'API privata. Ecco i passaggi:

  1. Dichiarare le autorizzazioni necessarie in AndroidManifest.xml:

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/> 
    <uses-permission 
        android:name="android.permission.PACKAGE_USAGE_STATS" 
        tools:ignore="ProtectedPermissions"/> 
    
    1. chiedere il permesso a Activity

    android.permission.PACKAGE_USAGE_STATS non è un permesso normale, non può essere richiesto semplicemente. Al fine di verificare, se l'autorizzazione è stata concessa, controllare:

    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; 
    } 
    

    Per richiedere questo permesso, è sufficiente chiamare Intent:

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

    è necessaria anche un'altra permmission: Manifest.permission.READ_PHONE_STATE. È necessario solo, quando è necessario ottenere mobile data statistics.Tuttavia, questo è il permesso normale quindi può essere requested as any other permission

    1. Usa NetworkStatsManager:

Realizzato un campione Github repo che dimostra l'utilizzo.

+1

Sono bloccato con READ_NETWORK_USAGE_HISTORY. provato il repository su un 6.0.1 e ottenuto un numero strano dal lato NetworkStatsManager. Sei sicuro che questo hack funzioni ancora? grazie mille! – martin

0
/* 
getting youtube usage for both mobile and wifi. 
*/ 
public long getYoutubeTotalusage(Context context) { 
    String subId = getSubscriberId(context, ConnectivityManager.TYPE_MOBILE); 
    return getYoutubeUsage(ConnectivityManager.TYPE_MOBILE, subId) + getYoutubeUsage(ConnectivityManager.TYPE_WIFI, ""); 
} 


private long getYoutubeUsage(int networkType, String subScriberId) { 
    NetworkStats networkStatsByApp; 
    long currentYoutubeUsage = 0L; 
    try { 
     networkStatsByApp = networkStatsManager.querySummary(networkType, subScriberId, 0, System.currentTimeMillis()); 
     do { 
      NetworkStats.Bucket bucket = new NetworkStats.Bucket(); 
      networkStatsByApp.getNextBucket(bucket); 
      if (bucket.getUid() == packageUid) { 
       //rajeesh : in some devices this is immediately looping twice and the second iteration is returning correct value. So result returning is moved to the end. 
       currentYoutubeUsage = (bucket.getRxBytes() + bucket.getTxBytes()); 
      } 
     } while (networkStatsByApp.hasNextBucket()); 

    } catch (RemoteException e) { 
     e.printStackTrace(); 
    } 

    return currentYoutubeUsage; 
} 


private String getSubscriberId(Context context, int networkType) { 
    if (ConnectivityManager.TYPE_MOBILE == networkType) { 
     TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 
     return tm.getSubscriberId(); 
    } 
    return ""; 
}