การติดตาม / ตรวจสอบการใช้ข้อมูล 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_opacketsifi_ipackets

นอกจากนี้ยังต้องการเพิ่มว่าถ้าฉันเชื่อมต่อกับเครือข่าย WiFi แต่ผมไม่ได้ใช้อินเทอร์เน็ตผมยังคงได้รับมูลค่าเพิ่มให้กับและifi_obytesifi_ibytes

อาจเป็นฉันผิดในการใช้งานหรือความเข้าใจ ต้องการใครสักคนที่จะช่วยฉันออก


แก้ไข: แทนที่จะAF_LINKลองAF_INET( sockaddr_inแทนsockaddr_dl) แอปพลิเคชันขัดข้อง

คำตอบ:


175

สิ่งนั้นpdp_ip0คือหนึ่งในอินเตอร์เฟสทั้งหมดpdpXXXคือWWANเชื่อมต่อที่ทุ่มเทให้กับฟังก์ชั่นที่แตกต่างกัน, ข้อความเสียง, อินเตอร์เฟซเครือข่ายทั่วไป

ฉันอ่านในฟอรัมของ Apple ว่า: ระบบปฏิบัติการไม่ได้เก็บสถิติเครือข่ายไว้เป็นขั้นตอน ดังนั้นจึงไม่มีวิธีแก้ไขปัญหานี้อย่างแน่นอน อย่างไรก็ตามคุณสามารถรับสถิติเครือข่ายสำหรับแต่ละอินเตอร์เฟสเครือข่ายได้

โดยทั่วไป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

20
คุณจำเป็นต้องนำเข้าห้องสมุดนี้: #include <อาภา / inet.h> #include <สุทธิ / if.h> #include <ifaddrs.h> #include <สุทธิ / if_dl.h>
user982705

9
เป็นไปได้ด้วยรหัสนี้เพื่อติดตามปริมาณข้อมูลต่อแอปพลิเคชัน iOS หรือไม่
fvisticot

2
@ Mat: โซลูชันที่ฉันออกแบบมาสำหรับลูกค้าองค์กรและไม่ได้ปรับใช้บน AppStore
Sahil Khanna

4
มีใครคิดวิธีการรับข้อมูลต่อแอพไหม แบ่งปันรหัสโปรด :)
Bob de Graaf

16

สิ่งสำคัญคือต้องเข้าใจว่าตัวนับเหล่านี้มีให้ตั้งแต่การบู๊ตครั้งสุดท้ายของอุปกรณ์

ดังนั้นเพื่อให้สามารถใช้งานได้อย่างมีประสิทธิภาพคุณควรติดตามตัวอย่างทุกครั้งพร้อมเวลาใช้งานของอุปกรณ์ (คุณสามารถใช้mach_absolute_time()- ดูสิ่งนี้สำหรับข้อมูลเพิ่มเติม)

เมื่อคุณมีตัวอย่างเคาน์เตอร์ + เวลาทำงานคุณสามารถมีฮิวริสติกที่ดีขึ้นตามการใช้ข้อมูล ...


mach_absolute_time ไม่ใช่เวลาทำงาน มันเป็นระยะเวลาโดยประมาณที่ CPU ใช้งานอยู่ mach_absolute_time ส่วนใหญ่หยุดนับเมื่ออุปกรณ์หลับ
บ๊อบวิทแมน

13

เพื่อเพิ่มคำตอบที่ยอมรับเป็นสิ่งสำคัญที่ต้องตระหนักว่าจำนวนข้อมูลที่แสดงโดยอินเตอร์เฟสล้นและเริ่มใหม่0ทุกครั้ง4 GBโดยเฉพาะถ้าคุณใช้รหัสนี้เพื่อคำนวณความแตกต่างระหว่างการอ่านสองครั้ง นี่เป็นเพราะifi_obytesและifi_ibytesเป็นuint_32และค่าสูงสุดของพวกเขาคือ4294967295และความคุ้มค่าสูงสุดของพวกเขาคือ

นอกจากนี้ฉันขอแนะนำให้ใช้unsigned ints สำหรับตัวแปรที่มีข้อมูลที่ส่งและรับ ปกติint s มีค่าสูงสุดครึ่งหนึ่งของจำนวนเต็มที่ไม่ได้ลงนามดังนั้นเมื่อเพิ่มifi_obytesอาจทำให้เกิดการล้นได้

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

4

คำตอบที่ได้รับการยอมรับอย่างรวดเร็ว ฉันยังแบ่งรหัสเป็นหน่วยที่เล็กลง

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

และค่านั้นมาจากการรีบูทครั้งล่าสุด ไม่มีทางรับเดือนที่ผ่านมาหรือปัจจุบัน?
Slavcho

@Slavcho จนกว่าจะถึงวันที่โพสต์นี้มันเป็นไปไม่ได้ ฉันยังไม่ได้ทำการวิจัยใหม่เกี่ยวกับเรื่องนี้หลังจาก iOS12 ฉันแนะนำให้คุณสะสม ir ในบางสถานที่เพื่อทำการกู้คืนหลังจากนั้น
dede.exe

0

ขออภัยสำหรับคำตอบเดียวกันอีกครั้ง

แต่ฉันพบว่า 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.