Pelacakan / Pemantauan Penggunaan Data iPhone


137

Saya telah mencari topik ini tetapi menemukan sangat sedikit detail yang berguna. Dengan detail tersebut saya sudah mencoba memasak beberapa kode sebagai berikut.

Catatan: Silakan bandingkan detail yang dibagikan dalam posting ini dengan posting lain sebelum menandai ini sebagai DUPLICATE, dan bukan hanya dengan subjeknya.

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

Kode ini mengumpulkan informasi penggunaan internet perangkat iPhone (dan bukan aplikasi saya sendiri).

Sekarang, jika saya menggunakan internet melalui WiFi atau melalui 3G, saya mendapatkan data (byte) hanya dalam ifi_obytes(dikirim) dan ifi_ibytes(diterima) tetapi saya pikir saya harus mendapatkan penggunaan WiFi di ifi_opacketsdan ifi_ipackets.

Juga ingin menambahkan bahwa jika saya terhubung ke jaringan WiFi, tetapi tidak menggunakan internet, saya masih mendapatkan nilai tambah ke ifi_obytesdan ifi_ibytes.

Mungkin saya salah dalam implementasi atau pemahamannya. Butuh seseorang untuk membantuku.


Sunting: Alih-alih AF_LINKsaya mencoba AF_INET( sockaddr_inbukan sockaddr_dl). Ini merusak aplikasi.

Jawaban:


177

Masalahnya adalah bahwa pdp_ip0salah satu antarmuka, semua pdpXXXadalah WWANantarmuka yang didedikasikan untuk fungsi yang berbeda, pesan suara, antarmuka jaringan umum.

Saya membaca di forum Apple bahwa: OS tidak menyimpan statistik jaringan berdasarkan proses demi proses. Karena itu, tidak ada solusi pasti untuk masalah ini. Namun, Anda dapat memperoleh statistik jaringan untuk setiap antarmuka jaringan.

Secara umum en0adalah Wi-Fiantarmuka Anda dan antarmuka pdp_ip0Anda WWAN.

Tidak ada cara yang baik untuk mendapatkan informasi wifi / data jaringan seluler sejak, tanggal-waktu tertentu!

Statistik data ( ifa_data->ifi_obytesdan ifa_data->ifi_ibytes) disimpan dari reboot perangkat sebelumnya.

Saya tidak tahu mengapa, tetapi ifi_opacketsdan ifi_ipacketsditampilkan hanya untuk lo0(menurut saya antarmuka utamanya).

Iya. Kemudian perangkat terhubung melalui WiFidan tidak menggunakan if_iobytesnilai internet masih datang karena metode ini menyediakan pertukaran byte jaringan dan bukan hanya internet.

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

Peningkatan dukungan salin / tempel!


1
Terima kasih banyak. Kode ini bekerja dengan sangat baik. Juga terima kasih telah menjelaskan barangnya.
Sahil Khanna

20
Anda perlu mengimpor pustaka ini: #include <arpa / inet.h> #include <net / if.h> #include <ifaddrs.h> #include <net / if_dl.h>
user982705

9
Apakah mungkin dengan kode ini untuk melacak lalu lintas data per aplikasi iOS?
fvisticot

2
@Mat: Solusi yang saya rancang jika untuk klien perusahaan dan tidak diterapkan di AppStore.
Sahil Khanna

4
Adakah yang tahu cara mendapatkan data per aplikasi? Tolong bagikan kodenya :)
Bob de Graaf

16

Penting untuk dipahami bahwa penghitung ini disediakan sejak boot terakhir perangkat.

Jadi, untuk memanfaatkannya secara efektif, Anda harus menemani setiap sampel dengan waktu aktif perangkat (Anda dapat menggunakan mach_absolute_time()- lihat ini untuk informasi lebih lanjut)

Setelah Anda memiliki sampel penghitung + waktu aktif, Anda dapat memiliki heuristik yang lebih baik untuk penggunaan data ...


mach_absolute_time bukan uptime. Ini kira-kira jumlah waktu CPU telah aktif. mach_absolute_time sebagian besar berhenti menghitung saat perangkat tidur.
Bob Whiteman

13

Untuk menambah jawaban yang diterima, penting untuk disadari bahwa jumlah data yang ditampilkan oleh antarmuka melimpah dan dimulai ulang 0setelah setiap 4 GB, terutama jika Anda menggunakan kode ini untuk menghitung perbedaan antara dua bacaan. Ini karena ifi_obytesdan ifi_ibytessedang uint_32dan nilai maksimalnya adalah 4294967295.

Juga, saya merekomendasikan menggunakan unsigned ints untuk variabel yang berisi data yang dikirim dan diterima. Regular ints memiliki setengah dari nilai maksimal dari unsigned integer, jadi saat ditambahkan ifi_obytes, ini dapat menyebabkan overflow.

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

4

Versi cepat dari jawaban yang diterima. Saya juga memecah kode menjadi unit yang lebih kecil.

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

Saya memperbaiki kode sumber di atas ke versi 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

Versi baru tentang berdasarkan versi sebelumnya, tetapi diadaptasi untuk Swift4 dan 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
    }
}

apakah itu ditampilkan untuk setiap aplikasi atau aplikasi sebenarnya di mana ia digunakan?
Maksim Kniazev

Ini penggunaan global ... Ini tidak dipisahkan oleh aplikasi.
dede.exe

Dan nilainya dari reboot terakhir. Tidak ada cara untuk mendapatkan bulan lalu / saat ini?
Slavcho

@Bayu_joo Sampai tanggal posting ini tidak mungkin. Saya masih belum melakukan penelitian baru tentangnya setelah iOS12. Saya menyarankan Anda untuk menumpuknya di suatu tempat untuk memulihkannya setelahnya.
dede.exe

0

Maaf untuk jawaban yang sama lagi.

tetapi saya menemukan bahwa UInt32 tidak cukup, jadi akan macet ketika menjadi terlalu besar.

Saya baru saja mengubah UInt32 menjadi UInt64 dan berfungsi dengan baik.

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
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.