carrier_info_plus 1.0.0 copy "carrier_info_plus: ^1.0.0" to clipboard
carrier_info_plus: ^1.0.0 copied to clipboard

Cellular carrier, SIM and network info for Flutter. Swift Package Manager ready, dual-SIM aware, and explicit about what modern iOS no longer reports.

carrier_info_plus #

Cellular carrier, SIM and network information for Flutter.

pub version license SwiftPM

A maintained replacement for the unmaintained carrier_info, built for Flutter 3.24+ with Swift Package Manager support, AGP 9-ready Gradle config, and typed enums instead of stringly-typed fields.

Important

This is not a drop-in replacement. The _plus suffix usually signals a compatible fork; this one is a ground-up rewrite with a different API. The old package advertised a lot of fields that modern Android and iOS no longer populate, and carrying those forward would have meant shipping a contract we could not honour. See Migrating below.


What each platform can actually tell you #

This is the part most carrier packages gloss over. Apple removed CTCarrier in iOS 16, so carrier identity is gone there for every app, no matter how well maintained the plugin is.

Android iOS 16+
Carrier name ❌ removed by Apple
MCC / MNC ❌ removed by Apple
Country ISO ❌ removed by Apple
Per-SIM enumeration (dual SIM) ❌ count only
SIM state ⚠️ inferred
Roaming
Radio technology (LTE / 5G NR)
Network generation
eSIM support
SMS / voice capability
Cellular data availability

Rather than handing you a struct full of unexplained nulls, every result carries a support block telling you what was answerable and why:

final info = await CarrierInfoPlus.get();

if (info.support.carrierIdentityAvailable) {
  showCarrier(info.primarySim?.carrierName);
} else if (info.support.limitation.isRecoverable) {
  showPermissionPrompt();   // Android, READ_PHONE_STATE not granted
} else {
  hideCarrierRow();         // iOS 16+, nothing to show and nothing to ask for
}

That distinction — "the user said no" versus "this OS will never answer" — is the whole reason this package exists. They look identical in the data and mean completely different things in a UI.


Install #

dependencies:
  carrier_info_plus: ^1.0.0

No iOS setup required. SwiftPM and CocoaPods are both supported, so it works whether or not your app has migrated.

Android permissions #

This package declares no permissions of its own. READ_PHONE_STATE is a runtime permission that appears in the Play Console and obliges you to file a data-safety declaration, so it's your call, not the package's.

Without any permission you still get: network operator, SIM state, and the active SIM's MCC/MNC and country. For per-SIM data on a dual-SIM device, add:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Then request it at runtime — either with your existing permission_handler setup, or with the built-in helper:

if (!await CarrierInfoPlus.hasPermission()) {
  await CarrierInfoPlus.requestPermission();
}

Usage #

import 'package:carrier_info_plus/carrier_info_plus.dart';

final info = await CarrierInfoPlus.get();

// Network — works on both platforms
print(info.generation);                   // NetworkGeneration.fiveG
print(info.network.radioTechnologies);    // [RadioAccessTechnology.nr]
print(info.network.cellularDataState);    // CellularDataState.notRestricted

// Device capabilities
print(info.capabilities.isMultiSimSupported);  // bool, not a String
print(info.capabilities.supportsEmbeddedSim);

// Per-SIM — Android
for (final sim in info.simCards) {
  print('${sim.slotIndex}: ${sim.carrierName} (${sim.plmn})');
  print('eSIM: ${sim.isEmbedded}, roaming: ${sim.isRoaming}');
}

get() returns a snapshot, not a live view. Nothing is cached, because SIM and network state change underneath you — re-read after a SIM swap or when returning from the background.

It never throws for the ordinary "cannot answer" cases. An unsupported platform, a missing permission and a device with no radio all come back as a populated CarrierInfo whose support block explains the gap. A PlatformException still propagates, because that means something genuinely broke.


Migrating from carrier_info #

The platform split is gone. Both getAndroidInfo() and getIosInfo() map to the same CarrierInfoPlus.get() — that repetition in the table is deliberate, not a typo. Why

carrier_info carrier_info_plus
CarrierInfo.getAndroidInfo() CarrierInfoPlus.get()
CarrierInfo.getIosInfo() CarrierInfoPlus.get()
AndroidCarrierData.subscriptionsInfo CarrierInfo.simCards
AndroidCarrierData.telephonyInfo CarrierInfo.network + CarrierInfo.simCards
AndroidCarrierData.isMultiSimSupported (String) capabilities.isMultiSimSupported (bool)
AndroidCarrierData.isVoiceCapable capabilities.isVoiceCapable
TelephonyInfo.networkGeneration (String) network.generation (NetworkGeneration)
TelephonyInfo.radioType (String) network.radioTechnologies (List<RadioAccessTechnology>)
TelephonyInfo.simState (String) SimCard.state (SimState)
IosCarrierData.carrierRadioAccessTechnologyTypeList network.radioTechnologies
IosCarrierData.supportsEmbeddedSIM capabilities.supportsEmbeddedSim
IosCarrierData.isSIMInserted CarrierInfo.hasSim
toMap()['_ios_version_info'] CarrierInfo.support

Why one call for both platforms #

The old API made you branch on platform to ask one question:

String? name;
if (Platform.isAndroid) {
  final d = await CarrierInfo.getAndroidInfo();
  name = d?.telephonyInfo.first.carrierName;
} else {
  final d = await CarrierInfo.getIosInfo();
  name = d?.carrierData?.first.carrierName;
}

Two return types, two field paths, two sets of null checks. Now:

final info = await CarrierInfoPlus.get();
final name = info.primarySim?.carrierName;

The platform difference hasn't vanished — it moved out of the type and into the data. iOS returns fewer populated fields, and support says why.

That's the better axis, because platform was never the thing that actually varied:

Carrier name
Android, READ_PHONE_STATE granted ✅ populated
Android, permission denied ❌ null
iOS 16+ ❌ null

Android already has the partial-data problem on its own. Splitting by platform never spared you from handling it — you just had to handle it again inside the Android branch, unaided. One shape with one support block covers all three rows, and adding a platform later is a new DataLimitation value rather than a new class and a new branch in every app.

You can still branch on Platform.isIOS if you want. But info.support.carrierIdentityAvailable is the better condition: it tests the thing you actually care about instead of a proxy for it.

Fields with no replacement #

These were removed because they no longer return data on a current OS:

Removed Why
simSerialNo Null since Android 10 for non-privileged apps
phoneNumber Empty on most carriers even with READ_PHONE_NUMBERS
cellId / lac Needs location permission for a GSM-only legacy path
iOS subscriberIdentifiers, carrierTokens Not obtainable on modern iOS

You can also delete five permissions from your manifest. This package needs only READ_PHONE_STATE, and only if you want per-SIM data. In particular, drop READ_PRIVILEGED_PHONE_STATE — it is signature-level, so no Play Store app can ever hold it, and listing it invites Play Console review questions for nothing.


Why iOS returns so little #

Apple deprecated CTCarrier in iOS 16. carrierName returns "--", mobileCountryCode and mobileNetworkCode return nil, and serviceSubscriberCellularProviders went with them.

This package deliberately ships no deprecated fallback for iOS 13-15. Two reasons: behaviour shouldn't silently change under your users as they update, and calling deprecated CoreTelephony API is a build break waiting to happen when Apple finally removes it. iOS reports carrier identity as unavailable on every version, consistently.

What remains genuinely readable on iOS is real and useful: radio access technology per active service, eSIM provisioning support, SMS capability, and whether your app may use cellular data.


Contributing #

Issues and pull requests welcome. The package is small on purpose — if you're adding a field, please include what OS versions actually populate it.

License #

MIT — see LICENSE.

2
likes
0
points
0
downloads

Publisher

verified publishermoulibheemaneti.com

Weekly Downloads

Cellular carrier, SIM and network info for Flutter. Swift Package Manager ready, dual-SIM aware, and explicit about what modern iOS no longer reports.

Repository (GitHub)
View/report issues

Topics

#carrier #sim #telephony #cellular #network

License

unknown (license)

Dependencies

flutter

More

Packages that depend on carrier_info_plus

Packages that implement carrier_info_plus