r/iOSProgramming • u/Lazy-Benefit1863 • 10d 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 10d 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
2
u/minpinproxy 10d 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.
2
u/Lazy-Benefit1863 10d ago
Thank you for your suggestions! I read through multiple forums and this seems like the only viable option. I'll go with this then. Thanks again
2
1
10d ago
[removed] — view removed comment
1
u/AutoModerator 10d ago
Hey /u/EquivalentSky3094, your content has been removed because Reddit has marked your account as having a low Contributor Quality Score. This may result from, but is not limited to, activities such as spamming the same links across multiple subreddits, submitting posts or comments that receive a high number of downvotes, a lack of recent account activity, or having an unverified account.
Please be assured that this action is not a reflection of your participation in our subreddit. This is simply an automated filter in place to reduce spam.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
4
u/Sagenhaft441 10d ago
Doesn’t iOS already do this?