iPhoneデータ使用量の追跡/監視


136

このトピックを検索しましたが、役立つ詳細はほとんど見つかりませんでした。これらの詳細を使用して、次のようにいくつかのコードを作成しようとしました。

注:この投稿で共有されている詳細を他の投稿と比較してから、件名だけでなく、DUPLICATEとしてマークしてください。

- (NSArray *)getDataCountersForType:(int)type {
    BOOL success;
    struct ifaddrs *addrs = nil;
    const struct ifaddrs *cursor = nil;
    const struct sockaddr_dl *dlAddr = nil;
    const struct if_data *networkStatisc = nil; 

    int dataSent = 0;
    int dataReceived = 0;

    success = getifaddrs(&addrs) == 0;
    if (success) {
        cursor = addrs;
        while (cursor != NULL) {
            if (cursor->ifa_addr->sa_family == AF_LINK) {
                dlAddr = (const struct sockaddr_dl *) cursor->ifa_addr;
                networkStatisc = (const struct if_data *) cursor->ifa_data;

                if (type == WiFi) {
                    dataSent += networkStatisc->ifi_opackets;
                    dataReceived += networkStatisc->ifi_ipackets;   
                }
                else if (type == WWAN) {
                    dataSent += networkStatisc->ifi_obytes;
                    dataReceived += networkStatisc->ifi_ibytes; 
                }
            }
            cursor = cursor->ifa_next;
        }
        freeifaddrs(addrs);
    }       
    return [NSArray arrayWithObjects:[NSNumber numberWithInt:dataSent], [NSNumber numberWithInt:dataReceived], nil];    
}

このコードは、iPhoneデバイスのインターネット使用に関する情報を収集します(アプリケーションのみではありません)。

ここで、WiFiまたは3Gを介してインターネットを使用する場合、データ(バイト)はifi_obytes(送信)とifi_ibytes(受信)でのみ取得されますが、ifi_opacketsおよびでWiFiの使用を取得する必要があると思いますifi_ipackets

また、私はWiFiネットワークに接続されているんだけど、インターネットを使用していない場合、私はまだ値が追加されますことを追加したいifi_obytesifi_ibytes

実装や理解が間違っているかもしれません。私を助ける誰かが必要です。


編集:AF_LINK私が試した代わりにAF_INETsockaddr_in代わりにsockaddr_dl)。これにより、アプリケーションがクラッシュします。

回答:


175

それpdp_ip0はインターフェースの1つであり、すべてpdpXXXWWANさまざまな機能、ボイスメール、一般的なネットワークインターフェース専用のインターフェースです。

私はAppleフォーラムで次のことを読みました:OSはプロセスごとにネットワーク統計を保持しません。そのため、この問題に対する正確な解決策はありません。ただし、各ネットワークインターフェイスのネットワーク統計を取得できます。

一般的にen0はあなたのWi-Fiインターフェースでpdp_ip0あり、あなたのWWANインターフェースです。

特定の日時以降、情報wifi /携帯電話ネットワークデータを取得する良い方法はありません!

データ統計(ifa_data->ifi_obytesおよびifa_data->ifi_ibytes)は、前回のデバイスの再起動から保存されます。

理由はわかりませんがifi_opackets、(主なインターフェイスだと思います)ifi_ipacketsだけを表示していlo0ます。

はい。次に、デバイスは経由で接続されWiFi、インターネットのif_iobytes値を使用しません。この方法では、インターネットだけでなく、ネットワークのバイト交換が提供されるためです。

#include <net/if.h>
#include <ifaddrs.h>

static NSString *const DataCounterKeyWWANSent = @"WWANSent";
static NSString *const DataCounterKeyWWANReceived = @"WWANReceived";
static NSString *const DataCounterKeyWiFiSent = @"WiFiSent";
static NSString *const DataCounterKeyWiFiReceived = @"WiFiReceived";

NSDictionary *DataCounters()
{
    struct ifaddrs *addrs;
    const struct ifaddrs *cursor;

    u_int32_t WiFiSent = 0;
    u_int32_t WiFiReceived = 0;
    u_int32_t WWANSent = 0;
    u_int32_t WWANReceived = 0;

    if (getifaddrs(&addrs) == 0)
    {
        cursor = addrs;
        while (cursor != NULL)
        {
            if (cursor->ifa_addr->sa_family == AF_LINK)
            {
#ifdef DEBUG
                const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data;
                if (ifa_data != NULL)
                {
                    NSLog(@"Interface name %s: sent %tu received %tu",cursor->ifa_name,ifa_data->ifi_obytes,ifa_data->ifi_ibytes);
                }
#endif

                // name of interfaces:
                // en0 is WiFi
                // pdp_ip0 is WWAN
                NSString *name = @(cursor->ifa_name);
                if ([name hasPrefix:@"en"])
                {
                    const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data;
                    if (ifa_data != NULL)
                    {
                        WiFiSent += ifa_data->ifi_obytes;
                        WiFiReceived += ifa_data->ifi_ibytes;
                    }
                }

                if ([name hasPrefix:@"pdp_ip"])
                {
                    const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data;
                    if (ifa_data != NULL)
                    {
                        WWANSent += ifa_data->ifi_obytes;
                        WWANReceived += ifa_data->ifi_ibytes;
                    }
                }
            }

            cursor = cursor->ifa_next;
        }

        freeifaddrs(addrs);
    }

    return @{DataCounterKeyWiFiSent : @(WiFiSent),
             DataCounterKeyWiFiReceived : @(WiFiReceived),
             DataCounterKeyWWANSent : @(WWANSent),
             DataCounterKeyWWANReceived : @(WWANReceived)};
}

改善されたコピー/貼り付けのサポート!


1
どうもありがとう。このコードは不思議に働きました。また、説明してくれてありがとう。
Sahil Khanna、2011年

20
このライブラリをインポートする必要があります。#include <arpa / inet.h> #include <net / if.h> #include <ifaddrs.h> #include <net / if_dl.h>
user982705

9
このコードを使用して、iOSアプリケーションごとにデータトラフィックを追跡することはできますか?
fvisticot 2012

2
@Mat:エンタープライズクライアント向けで、AppStoreに展開されていない場合に設計したソリューション。
Sahil Khanna

4
アプリごとにデータを取得する方法を誰かが理解しましたか?コードを共有してください:)
Bob de Graaf、2015年

16

これらのカウンタは、デバイスの最後の起動以降に提供されることを理解することが重要です。

したがって、それらを効果的に使用するには、すべてのサンプルにデバイスの稼働時間を伴う必要があります(使用できますmach_absolute_time()-詳細については、こちらを参照してください)。

カウンターサンプルと稼働時間を取得すると、データの使用に関してより優れたヒューリスティックを使用できます...


mach_absolute_timeは稼働時間ではありません。おおよそ、CPUがアクティブであった時間です。mach_absolute_timeは、デバイスがスリープするときにほとんどカウントを停止します。
ボブホワイトマン

13

受け入れられた回答に追加するには、特にこのコードを使用して2つの読み取り値の差を計算している場合は、インターフェースによって表示されるデータの量が0毎回オーバーフローして再起動することを認識することが重要4 GBです。これは、ifi_obytesおよびでifi_ibytesありuint_32、それらの最大値がであるためです4294967295

また、unsigned int送受信されるデータを含む変数にはsを使用することをお勧めします。通常intのは、符号なし整数の最大値の半分であるため、を追加ifi_obytesすると、オーバーフローが発生する可能性があります。

unsigned int sent = 0;
sent += networkStatisc->ifi_obytes;

4

受け入れられた回答のSwiftバージョン。また、コードを小さな単位に分割します。

struct DataUsageInfo {
    var wifiReceived: UInt32 = 0
    var wifiSent: UInt32 = 0
    var wirelessWanDataReceived: UInt32 = 0
    var wirelessWanDataSent: UInt32 = 0

    mutating func updateInfoByAdding(info: DataUsageInfo) {
        wifiSent += info.wifiSent
        wifiReceived += info.wifiReceived
        wirelessWanDataSent += info.wirelessWanDataSent
        wirelessWanDataReceived += info.wirelessWanDataReceived
    }
}

class DataUsage {

    private static let wwanInterfacePrefix = "pdp_ip"
    private static let wifiInterfacePrefix = "en"

    class func getDataUsage() -> DataUsageInfo {
        var interfaceAddresses: UnsafeMutablePointer<ifaddrs> = nil
        var dataUsageInfo = DataUsageInfo()

        guard getifaddrs(&interfaceAddresses) == 0 else { return dataUsageInfo }

        var pointer = interfaceAddresses
        while pointer != nil {
            guard let info = getDataUsageInfo(from: pointer) else {
                pointer = pointer.memory.ifa_next
                continue
            }
            dataUsageInfo.updateInfoByAdding(info)
            pointer = pointer.memory.ifa_next
        }

        freeifaddrs(interfaceAddresses)

        return dataUsageInfo
    }

    private class func getDataUsageInfo(from infoPointer: UnsafeMutablePointer<ifaddrs>) -> DataUsageInfo? {
        let pointer = infoPointer

        let name: String! = String.fromCString(infoPointer.memory.ifa_name)

        let addr = pointer.memory.ifa_addr.memory
        guard addr.sa_family == UInt8(AF_LINK) else { return nil }

        return dataUsageInfo(from: pointer, name: name)
    }

    private class func dataUsageInfo(from pointer: UnsafeMutablePointer<ifaddrs>, name: String) -> DataUsageInfo {
        var networkData: UnsafeMutablePointer<if_data> = nil
        var dataUsageInfo = DataUsageInfo()

        if name.hasPrefix(wifiInterfacePrefix) {
            networkData = unsafeBitCast(pointer.memory.ifa_data, UnsafeMutablePointer<if_data>.self)
            dataUsageInfo.wifiSent += networkData.memory.ifi_obytes
            dataUsageInfo.wifiReceived += networkData.memory.ifi_ibytes
        } else if name.hasPrefix(wwanInterfacePrefix) {
            networkData = unsafeBitCast(pointer.memory.ifa_data, UnsafeMutablePointer<if_data>.self)
            dataUsageInfo.wirelessWanDataSent += networkData.memory.ifi_obytes
            dataUsageInfo.wirelessWanDataReceived += networkData.memory.ifi_ibytes
        }

        return dataUsageInfo
    }
}

4

上記のソースコードをSwift3バージョンに修正しました

struct DataUsageInfo {
    var wifiReceived: UInt32 = 0
    var wifiSent: UInt32 = 0
    var wirelessWanDataReceived: UInt32 = 0
    var wirelessWanDataSent: UInt32 = 0

    mutating func updateInfoByAdding(_ info: DataUsageInfo) {
        wifiSent += info.wifiSent
        wifiReceived += info.wifiReceived
        wirelessWanDataSent += info.wirelessWanDataSent
        wirelessWanDataReceived += info.wirelessWanDataReceived
    }
}


class DataUsage {

    private static let wwanInterfacePrefix = "pdp_ip"
    private static let wifiInterfacePrefix = "en"

    class func getDataUsage() -> DataUsageInfo {
        var ifaddr: UnsafeMutablePointer<ifaddrs>?
        var dataUsageInfo = DataUsageInfo()

        guard getifaddrs(&ifaddr) == 0 else { return dataUsageInfo }
        while let addr = ifaddr {
            guard let info = getDataUsageInfo(from: addr) else {
                ifaddr = addr.pointee.ifa_next
                continue
            }
            dataUsageInfo.updateInfoByAdding(info)
            ifaddr = addr.pointee.ifa_next
        }

        freeifaddrs(ifaddr)

        return dataUsageInfo
    }

    private class func getDataUsageInfo(from infoPointer: UnsafeMutablePointer<ifaddrs>) -> DataUsageInfo? {
        let pointer = infoPointer
        let name: String! = String(cString: pointer.pointee.ifa_name)
        let addr = pointer.pointee.ifa_addr.pointee
        guard addr.sa_family == UInt8(AF_LINK) else { return nil }

        return dataUsageInfo(from: pointer, name: name)
    }

    private class func dataUsageInfo(from pointer: UnsafeMutablePointer<ifaddrs>, name: String) -> DataUsageInfo {
        var networkData: UnsafeMutablePointer<if_data>?
        var dataUsageInfo = DataUsageInfo()

        if name.hasPrefix(wifiInterfacePrefix) {
            networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
            if let data = networkData {
                dataUsageInfo.wifiSent += data.pointee.ifi_obytes
                dataUsageInfo.wifiReceived += data.pointee.ifi_ibytes
            }

        } else if name.hasPrefix(wwanInterfacePrefix) {
            networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
            if let data = networkData {
                dataUsageInfo.wirelessWanDataSent += data.pointee.ifi_obytes
                dataUsageInfo.wirelessWanDataReceived += data.pointee.ifi_ibytes
            }
        }

        return dataUsageInfo
    }
}

4

以前のバージョンに基づいた新しいバージョンですが、Swift4とXcode 9に適合しています

struct DataUsageInfo {
    var wifiReceived: UInt32 = 0
    var wifiSent: UInt32 = 0
    var wirelessWanDataReceived: UInt32 = 0
    var wirelessWanDataSent: UInt32 = 0

    mutating func updateInfoByAdding(info: DataUsageInfo) {
        wifiSent += info.wifiSent
        wifiReceived += info.wifiReceived
        wirelessWanDataSent += info.wirelessWanDataSent
        wirelessWanDataReceived += info.wirelessWanDataReceived
    }
}

class DataUsage {

    private static let wwanInterfacePrefix = "pdp_ip"
    private static let wifiInterfacePrefix = "en"

    class func getDataUsage() -> DataUsageInfo {
        var interfaceAddresses: UnsafeMutablePointer<ifaddrs>? = nil

        var dataUsageInfo = DataUsageInfo()

        guard getifaddrs(&interfaceAddresses) == 0 else { return dataUsageInfo }

        var pointer = interfaceAddresses
        while pointer != nil {
            guard let info = getDataUsageInfo(from: pointer!) else {
                pointer = pointer!.pointee.ifa_next
                continue
            }
            dataUsageInfo.updateInfoByAdding(info: info)
            pointer = pointer!.pointee.ifa_next
        }

        freeifaddrs(interfaceAddresses)

        return dataUsageInfo
    }

    private class func getDataUsageInfo(from infoPointer: UnsafeMutablePointer<ifaddrs>) -> DataUsageInfo? {
        let pointer = infoPointer

        let name: String! = String(cString: infoPointer.pointee.ifa_name)
        let addr = pointer.pointee.ifa_addr.pointee
        guard addr.sa_family == UInt8(AF_LINK) else { return nil }

        return dataUsageInfo(from: pointer, name: name)
    }

    private class func dataUsageInfo(from pointer: UnsafeMutablePointer<ifaddrs>, name: String) -> DataUsageInfo {
        var networkData: UnsafeMutablePointer<if_data>? = nil
        var dataUsageInfo = DataUsageInfo()

        if name.hasPrefix(wifiInterfacePrefix) {
            networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
            dataUsageInfo.wifiSent += networkData?.pointee.ifi_obytes ?? 0
            dataUsageInfo.wifiReceived += networkData?.pointee.ifi_ibytes ?? 0
        } else if name.hasPrefix(wwanInterfacePrefix) {
            networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
            dataUsageInfo.wirelessWanDataSent += networkData?.pointee.ifi_obytes ?? 0
            dataUsageInfo.wirelessWanDataReceived += networkData?.pointee.ifi_ibytes ?? 0
        }

        return dataUsageInfo
    }
}

各アプリまたはそれが使用される実際のアプリに表示されますか?
Maksim Kniazev

これはグローバルな使用法です...アプリによって分離されていません。
dede.exe 2018年

そして、値は最後の再起動からのものです。過去/現在の月を取得する方法はありませんか?
Slavcho 2018年

@Slavcho。この投稿日まで、それは不可能でした。iOS12以降、私はまだそれについて新しい調査をしていません。後で回復するには、どこかにirを蓄積することをお勧めします。
dede.exe 2018年

0

同じ答えをもう一度申し訳ありません。

しかし、UInt32では十分ではないことがわかったため、UInt32が大きくなりすぎるとクラッシュします。

UInt32をUInt64に変更したところ、問題なく動作しました。

struct DataUsageInfo {
    var wifiReceived: UInt64 = 0
    var wifiSent: UInt64 = 0
    var wirelessWanDataReceived: UInt64 = 0
    var wirelessWanDataSent: UInt64 = 0

    mutating func updateInfoByAdding(info: DataUsageInfo) {
        wifiSent += info.wifiSent
        wifiReceived += info.wifiReceived
        wirelessWanDataSent += info.wirelessWanDataSent
        wirelessWanDataReceived += info.wirelessWanDataReceived
    }
}

class DataUsage {

    private static let wwanInterfacePrefix = "pdp_ip"
    private static let wifiInterfacePrefix = "en"

    class func getDataUsage() -> DataUsageInfo {
        var interfaceAddresses: UnsafeMutablePointer<ifaddrs>? = nil

        var dataUsageInfo = DataUsageInfo()

        guard getifaddrs(&interfaceAddresses) == 0 else { return dataUsageInfo }

        var pointer = interfaceAddresses
        while pointer != nil {
            guard let info = getDataUsageInfo(from: pointer!) else {
                pointer = pointer!.pointee.ifa_next
                continue
            }
            dataUsageInfo.updateInfoByAdding(info: info)
            pointer = pointer!.pointee.ifa_next
        }

        freeifaddrs(interfaceAddresses)

        return dataUsageInfo
    }

    private class func getDataUsageInfo(from infoPointer: UnsafeMutablePointer<ifaddrs>) -> DataUsageInfo? {
        let pointer = infoPointer

        let name: String! = String(cString: infoPointer.pointee.ifa_name)
        let addr = pointer.pointee.ifa_addr.pointee
        guard addr.sa_family == UInt8(AF_LINK) else { return nil }

        return dataUsageInfo(from: pointer, name: name)
    }

    private class func dataUsageInfo(from pointer: UnsafeMutablePointer<ifaddrs>, name: String) -> DataUsageInfo {
        var networkData: UnsafeMutablePointer<if_data>? = nil
        var dataUsageInfo = DataUsageInfo()

        if name.hasPrefix(wifiInterfacePrefix) {
            networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
            dataUsageInfo.wifiSent += UInt64(networkData?.pointee.ifi_obytes ?? 0)
            dataUsageInfo.wifiReceived += UInt64(networkData?.pointee.ifi_ibytes ?? 0)
        } else if name.hasPrefix(wwanInterfacePrefix) {
            networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
            dataUsageInfo.wirelessWanDataSent += UInt64(networkData?.pointee.ifi_obytes ?? 0)
            dataUsageInfo.wirelessWanDataReceived += UInt64(networkData?.pointee.ifi_ibytes ?? 0)
        }

        return dataUsageInfo
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.