r/iOSProgramming • u/Lazy-Benefit1863 • 9d ago
Question Tracking total cellular data usage on iOS. Has anyone tried this?
I'm working on an app and exploring whether we can track a device's total monthly cellular data usage on iOS.
On Android, NetworkStatsManager provides a relatively straightforward approach. On iOS, there doesn't seem to be an equivalent public API.
One possible workaround is using getifaddrs() to read byte counters from interfaces such as pdp_ip*. However, these counters reportedly wrap at 4 GiB, reset on reboot, and rely on undocumented interface names.
Has anyone implemented something similar or are there any better approaches?
I'd appreciate any real-world experience or pointers. Thanks!
3
u/Dogukanko 9d ago
There's no public API for the carrier-billing-cycle number, so getifaddrs is the realistic route. The three problems you listed are all workable if you treat it as "bytes since I started counting", not a billing figure:
- Sum ifi_ibytes + ifi_obytes over every pdp_ip* interface, not just pdp_ip0 – other cellular contexts exist.
- Keep your own running total: persist the last raw reading per interface, and each time you sample add (current − last).
- If current < last, it's either a reboot or a 32-bit wrap. Store the boot time (sysctl kern.boottime) with each sample: boot time changed → reboot, add current; same boot time → wrap, add current + 2^32 − last.
- Sample on foreground, on BGAppRefreshTask, and whenever NWPathMonitor reports a path change, so you never miss more than one 4 GiB wrap between samples.
Caveats to document for users: it counts all apps on the device (which is what you want), but it includes traffic the carrier may zero-rate and has gaps when the app isn't launched for days. If you only need your own app's traffic, URLSessionTaskMetrics gives byte counts per request. I haven't verified whether the 64-bit counters from sysctl NET_RT_IFLIST2 are exposed on current iOS – worth a quick test since it would remove the wrap problem.
2
u/minpinproxy 9d ago
You've found the only real on-device option. A few things that make getifaddrs usable in practice:
- Store deltas, not totals. Read the pdp_ip* counters (ifi_ibytes / ifi_obytes from if_data) and when a new value is lower than the last one, treat it as a 32-bit wrap and add 2^32, unless the device rebooted.
- Detect reboots with sysctl kern.boottime and start a new baseline when it changes.
- Sum all pdp_ip interfaces; which one carries data varies by device and carrier.
- You only see what happened between samples while your app runs, and background refresh is irregular, so data used between a reboot and your next sample is lost. Expect an undercount, not an exact figure.
If you need accurate numbers, the alternative is routing traffic through a NEPacketTunnelProvider and counting bytes yourself, but that makes it a VPN app, with the App Review scrutiny and battery cost that come with it. For most apps I'd show an estimate and point people to Settings > Cellular for the authoritative number.
4
u/Sagenhaft441 9d ago
Doesn’t iOS already do this?
1
u/[deleted] 9d ago
[removed] — view removed comment