Track cellular data usage using swift
Updated to Swift 4 you can use this easy extension. To track the device cell and wifi Usage.
extension SystemDataUsage {
public static var wifiCompelete: UInt64 {
return SystemDataUsage.getDataUsage().wifiSent + SystemDataUsage.getDataUsage().wifiReceived
}
public static var wwanCompelete: UInt64 {
return SystemDataUsage.getDataUsage().wirelessWanDataSent + SystemDataUsage.getDataUsage().wirelessWanDataReceived
}
}
class SystemDataUsage {
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 += UInt64(data.pointee.ifi_obytes)
dataUsageInfo.wifiReceived += UInt64(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 += UInt64(data.pointee.ifi_obytes)
dataUsageInfo.wirelessWanDataReceived += UInt64(data.pointee.ifi_ibytes)
}
}
return dataUsageInfo
}
}
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
}
}
You can use it like: SystemDataUsage.wifiCompelete
Tracking iPhone Data Usage
Swift 4
Sample Usage
let usage = getDataUsage()
// prints '3527660544 bytes of wifi'
print("\(usage.wifi.sent) bytes of wifi")
// prints '3.29 GB of wifi'
let usageString = ByteCountFormatter.string(fromByteCount: Int64(usage.wifi.sent), countStyle: .binary)
print("\(usageString) of wifi")
Code
import Foundation
typealias DataUsage = (wifi: (sent: UInt32, received: UInt32), wwan: (sent: UInt32, received: UInt32))
func getDataUsage() -> DataUsage {
var interfaceAddresses: UnsafeMutablePointer<ifaddrs>?
let status = getifaddrs(&interfaceAddresses)
defer { freeifaddrs(interfaceAddresses) }
var returnData = DataUsage((0, 0), (0, 0))
guard status == 0, let addresses = interfaceAddresses else { return returnData }
for pointer in AddressSequence(interfaceAddresses: addresses) {
guard pointer.pointee.ifa_addr.pointee.sa_family == AF_LINK else { continue }
let networkData = unsafeBitCast(pointer.pointee.ifa_data, to: UnsafeMutablePointer<if_data>.self)
let (bytesIn, bytesOut) = (networkData.pointee.ifi_ibytes, networkData.pointee.ifi_obytes)
let name = String(cString: pointer.pointee.ifa_name)
if name.hasPrefix("en") {
returnData.wifi.sent += bytesOut
returnData.wifi.received += bytesIn
} else if name.hasPrefix("pdp_ip") {
returnData.wwan.sent += bytesOut
returnData.wwan.received += bytesIn
}
}
return returnData
}
class AddressSequence: Sequence {
init(interfaceAddresses: UnsafeMutablePointer<ifaddrs>) {
self.interfaceAddresses = interfaceAddresses
}
let interfaceAddresses: UnsafeMutablePointer<ifaddrs>
typealias Element = UnsafeMutablePointer<ifaddrs>
func makeIterator() -> AddressIterator {
return AddressIterator(currentPointer: interfaceAddresses)
}
}
class AddressIterator: IteratorProtocol {
init(currentPointer: UnsafeMutablePointer<ifaddrs>) {
self.currentPointer = currentPointer
}
var currentPointer: UnsafeMutablePointer<ifaddrs>?
public func next() -> UnsafeMutablePointer<ifaddrs>? {
currentPointer = currentPointer?.pointee.ifa_next ?? nil
return currentPointer
}
}
Old Version
Here's one possible implementation.
First, include ifaddrs
in your Objective-C bridging header:
#include <ifaddrs.h>
Then, try out this function:
func getDataUsage() -> (wifi : (sent : UInt32, received : UInt32), wwan : (sent : UInt32, received : UInt32)) {
var interfaceAddresses : UnsafeMutablePointer<ifaddrs> = nil
var networkData: UnsafeMutablePointer<if_data> = nil
var returnTuple : (wifi : (sent : UInt32, received : UInt32), wwan : (sent : UInt32, received : UInt32)) = ((0, 0), (0, 0))
if getifaddrs(&interfaceAddresses) == 0 {
for var pointer = interfaceAddresses; pointer != nil; pointer = pointer.memory.ifa_next {
let name : String! = String.fromCString(pointer.memory.ifa_name)
println(name);
let flags = Int32(pointer.memory.ifa_flags)
var addr = pointer.memory.ifa_addr.memory
if addr.sa_family == UInt8(AF_LINK) {
if name.hasPrefix("en") {
networkData = unsafeBitCast(pointer.memory.ifa_data, UnsafeMutablePointer<if_data>.self)
returnTuple.wifi.sent += networkData.memory.ifi_obytes
returnTuple.wifi.received += networkData.memory.ifi_ibytes
} else if name.hasPrefix("pdp_ip") {
networkData = unsafeBitCast(pointer.memory.ifa_data, UnsafeMutablePointer<if_data>.self)
returnTuple.wwan.sent += networkData.memory.ifi_obytes
returnTuple.wwan.received += networkData.memory.ifi_ibytes
}
}
}
freeifaddrs(interfaceAddresses)
}
return returnTuple
}
It returns nested Swift tuples representing the four pieces of data you requested. This makes it easy to access. For example:
let usage = getDataUsage()
let wifiDataSentString = "WiFi Data Sent: \(usage.wifi.sent)"
iPhone Data Usage Tracking/Monitoring
The thing is that pdp_ip0
is one of interfaces, all pdpXXX
are WWAN
interfaces dedicated to different functions, voicemail, general networking interface.
I read in Apple forum that :
The OS does not keep network statistics on a process-by-process basis. As such, there's no exact solution to this problem. You can, however, get network statistics for each network interface.
In general en0
is your Wi-Fi
interface and pdp_ip0
is your WWAN
interface.
There is no good way to get information wifi/cellular network data since, particular date-time!
Data statistic (ifa_data->ifi_obytes
and ifa_data->ifi_ibytes
) are stored from previous device reboot.
I don't know why, but ifi_opackets
and ifi_ipackets
are shown just for lo0
(I think its main interface ).
Yes. Then device is connected via WiFi
and doesn't use internet if_iobytes
values still come because this method provides network bytes exchanges and not just 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)};
}
Improved copy/paste support !
Related Topics
Why Must a Protocol Operator Be Implemented as a Global Function
Facebook App Invites Notification Not Working in iOS
Com.Facebook.Sdk Error 2 on iOS
Choosing Units with Measurementformatter
iOS 5 Gm: <Error>: More Than Maximum 5 Filtered Album Lists Trying to Register. This Will Fail
Fbsession.Activesession.Isopen Returns No Even Though the User Logged-In
Are Storyboards Going to Work on iOS 4
How to Convert Video (In Gallery) to Nsdata? in Swift
How to Permanently Allow Usage of Camera on Trusted Websites with iOS - Safari
Uiscrollview with iOS Auto Layout Constraints: Wrong Size for Subviews
Ignore Manual Entries from Apple Health App as Data Source
Locking Orientation Does Not Work on iPad iOS 8 Swift Xcode 6.2
Nsdata to Nsstring with JSON Response
How to Get All Available Wifi Network Name Listings in iOS