Skip to content

Commit 53a3897

Browse files
authored
feat: add carrier information (#56)
* feat: add carrier related apis * feat: add native impl * docs: carrier apis * docs: changeset
1 parent e098443 commit 53a3897

File tree

6 files changed

+367
-0
lines changed

6 files changed

+367
-0
lines changed

.changeset/hungry-cups-hear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'react-native-nitro-device-info': patch
3+
---
4+
5+
feat: add carrier informations

docs/docs/api/device-info.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,87 @@ const carrier = await DeviceInfoModule.getCarrier();
482482
const carrierSync = DeviceInfoModule.getCarrierSync();
483483
```
484484

485+
### Carrier Information Properties
486+
487+
Detailed carrier information for telecom apps, analytics, and geo-detection.
488+
489+
#### `carrierAllowsVOIP: boolean`
490+
491+
Check if carrier allows VoIP calls on its network.
492+
493+
```typescript
494+
const allowsVOIP = DeviceInfoModule.carrierAllowsVOIP;
495+
// iOS: true/false based on carrier policy
496+
// Android: always true (no equivalent API)
497+
```
498+
499+
**Platform**: iOS only (always returns `true` on Android)
500+
501+
#### `carrierIsoCountryCode: string`
502+
503+
Get ISO 3166-1 alpha-2 country code for the carrier.
504+
505+
```typescript
506+
const countryCode = DeviceInfoModule.carrierIsoCountryCode;
507+
// Example: "US", "KR", "JP", "DE"
508+
// Returns "" if no SIM card
509+
```
510+
511+
**Platform**: iOS, Android
512+
513+
#### `mobileCountryCode: string`
514+
515+
Get Mobile Country Code (MCC) per ITU-T Recommendation E.212.
516+
517+
```typescript
518+
const mcc = DeviceInfoModule.mobileCountryCode;
519+
// Example: "310" (USA), "450" (Korea), "440" (Japan)
520+
// Returns "" if no carrier
521+
```
522+
523+
**Platform**: iOS, Android
524+
525+
**Common MCC values**:
526+
527+
| Country | MCC |
528+
|---------|-----|
529+
| USA | 310-316 |
530+
| Korea | 450 |
531+
| Japan | 440-441 |
532+
| China | 460 |
533+
| Germany | 262 |
534+
535+
#### `mobileNetworkCode: string`
536+
537+
Get Mobile Network Code (MNC) that identifies the carrier within a country.
538+
539+
```typescript
540+
const mnc = DeviceInfoModule.mobileNetworkCode;
541+
// Example: "260" (T-Mobile US), "05" (SKT Korea)
542+
// Returns "" if no carrier
543+
```
544+
545+
**Platform**: iOS, Android
546+
547+
#### `mobileNetworkOperator: string`
548+
549+
Get combined MCC + MNC string.
550+
551+
```typescript
552+
const operator = DeviceInfoModule.mobileNetworkOperator;
553+
// Example: "310260" (T-Mobile US), "45005" (SKT Korea)
554+
// Equivalent to: mobileCountryCode + mobileNetworkCode
555+
// Returns "" if no carrier
556+
```
557+
558+
**Platform**: iOS, Android
559+
560+
**Use cases**:
561+
- Carrier-specific feature toggling
562+
- Regional content delivery
563+
- Telecom analytics
564+
- Fraud detection (geo-location verification)
565+
485566
### `isLocationEnabled(): Promise<boolean>`
486567

487568
Check if location services are enabled.
@@ -1066,6 +1147,8 @@ This provides fast access while keeping data reasonably fresh.
10661147
| deviceYearClass ||| Extended 2025 algorithm |
10671148
| isSideLoadingEnabled ||| Android only (per-app on 8.0+) |
10681149
| Network info ||| MAC hardcoded on iOS 7+ |
1150+
| Carrier info (MCC/MNC) ||| Empty string if no SIM |
1151+
| carrierAllowsVOIP || ⚠️ | Android always returns true |
10691152
| System language ||| BCP 47 format |
10701153
| Navigation mode ||| Android only (API 29+) |
10711154
| Android Build info ||| Android only |

docs/docs/api/migration.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,72 @@ Both libraries use the same Facebook algorithm for calculating device year class
553553
- Android: Checks su binaries, root apps, system properties, test-keys
554554
- iOS: Checks Cydia, jailbreak files, sandbox escape, suspicious paths
555555

556+
---
557+
558+
## Migrating from react-native-carrier-info
559+
560+
If you're using `react-native-carrier-info` for carrier information, you can consolidate into `react-native-nitro-device-info`.
561+
562+
### API Migration Reference
563+
564+
| react-native-carrier-info | react-native-nitro-device-info | Notes |
565+
|---------------------------|-------------------------------|-------|
566+
| `await CarrierInfo.allowsVOIP()` | `DeviceInfoModule.carrierAllowsVOIP` | Now sync property |
567+
| `await CarrierInfo.carrierName()` | `DeviceInfoModule.getCarrierSync()` | Now sync method |
568+
| `await CarrierInfo.isoCountryCode()` | `DeviceInfoModule.carrierIsoCountryCode` | Now sync property |
569+
| `await CarrierInfo.mobileCountryCode()` | `DeviceInfoModule.mobileCountryCode` | Now sync property |
570+
| `await CarrierInfo.mobileNetworkCode()` | `DeviceInfoModule.mobileNetworkCode` | Now sync property |
571+
| `await CarrierInfo.mobileNetworkOperator()` | `DeviceInfoModule.mobileNetworkOperator` | Now sync property |
572+
573+
### Migration Example
574+
575+
**Before** (`react-native-carrier-info`):
576+
```typescript
577+
import CarrierInfo from 'react-native-carrier-info';
578+
579+
async function getCarrierDetails() {
580+
const carrierName = await CarrierInfo.carrierName();
581+
const allowsVOIP = await CarrierInfo.allowsVOIP();
582+
const isoCountryCode = await CarrierInfo.isoCountryCode();
583+
const mcc = await CarrierInfo.mobileCountryCode();
584+
const mnc = await CarrierInfo.mobileNetworkCode();
585+
const operator = await CarrierInfo.mobileNetworkOperator();
586+
587+
return { carrierName, allowsVOIP, isoCountryCode, mcc, mnc, operator };
588+
}
589+
```
590+
591+
**After** (`react-native-nitro-device-info`):
592+
```typescript
593+
import { DeviceInfoModule } from 'react-native-nitro-device-info';
594+
595+
function getCarrierDetails() {
596+
// All synchronous - no async/await needed!
597+
return {
598+
carrierName: DeviceInfoModule.getCarrierSync(),
599+
allowsVOIP: DeviceInfoModule.carrierAllowsVOIP,
600+
isoCountryCode: DeviceInfoModule.carrierIsoCountryCode,
601+
mcc: DeviceInfoModule.mobileCountryCode,
602+
mnc: DeviceInfoModule.mobileNetworkCode,
603+
operator: DeviceInfoModule.mobileNetworkOperator,
604+
};
605+
}
606+
```
607+
608+
### Key Benefits
609+
610+
1. **No async/await**: All carrier properties are synchronous
611+
2. **Single dependency**: No need to install separate carrier-info package
612+
3. **JSI performance**: Zero-overhead native access via Nitro Modules
613+
4. **Unified API**: Carrier info alongside 80+ other device properties
614+
615+
### Platform Notes
616+
617+
- **iOS**: Uses `CTTelephonyNetworkInfo` and `CTCarrier` APIs
618+
- **Android**: Uses `TelephonyManager` APIs
619+
- **carrierAllowsVOIP**: Returns actual value on iOS, always `true` on Android (no equivalent API)
620+
- **Empty strings**: All properties return `""` when no SIM card is present
621+
556622
## Need Help?
557623

558624
- [Complete API Reference](/api/device-info)

packages/react-native-nitro-device-info/android/src/main/java/com/margelo/nitro/nitrodeviceinfo/DeviceInfo.kt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,73 @@ class DeviceInfo : HybridDeviceInfoSpec() {
895895
return cachedCarrier
896896
}
897897

898+
// MARK: - Carrier Information (react-native-carrier-info parity)
899+
900+
/** Cached TelephonyManager for carrier info APIs */
901+
private val carrierTelephonyManager: TelephonyManager? by lazy {
902+
context.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
903+
}
904+
905+
/**
906+
* Check if carrier allows VoIP calls on its network
907+
*
908+
* Android does not have an equivalent API to iOS's CTCarrier.allowsVOIP.
909+
* Always returns true per react-native-carrier-info implementation.
910+
*/
911+
override val carrierAllowsVOIP: Boolean
912+
get() = true
913+
914+
/**
915+
* ISO 3166-1 country code for the carrier
916+
*
917+
* Returns the ISO country code (e.g., "US", "KR", "JP") or empty string if unavailable.
918+
* Uses TelephonyManager.getSimCountryIso() for SIM-based country detection.
919+
*/
920+
override val carrierIsoCountryCode: String
921+
get() = carrierTelephonyManager?.simCountryIso?.uppercase() ?: ""
922+
923+
/**
924+
* Mobile Country Code (MCC)
925+
*
926+
* Returns 3-digit MCC per ITU-T E.212 (e.g., "310" for USA, "450" for Korea).
927+
* Parsed from TelephonyManager.getSimOperator() which returns MCC+MNC.
928+
* Returns empty string if unavailable or invalid.
929+
*/
930+
override val mobileCountryCode: String
931+
get() {
932+
val operator = carrierTelephonyManager?.simOperator
933+
if (operator.isNullOrEmpty() || operator.length < 3) {
934+
return ""
935+
}
936+
return operator.substring(0, 3)
937+
}
938+
939+
/**
940+
* Mobile Network Code (MNC)
941+
*
942+
* Returns 2 or 3-digit MNC (e.g., "260" for T-Mobile US).
943+
* Parsed from TelephonyManager.getSimOperator() which returns MCC+MNC.
944+
* Returns empty string if unavailable or invalid.
945+
*/
946+
override val mobileNetworkCode: String
947+
get() {
948+
val operator = carrierTelephonyManager?.simOperator
949+
if (operator.isNullOrEmpty() || operator.length < 5) {
950+
return ""
951+
}
952+
return operator.substring(3)
953+
}
954+
955+
/**
956+
* Mobile Network Operator (MCC + MNC combined)
957+
*
958+
* Returns combined MCC+MNC (e.g., "310260" for T-Mobile US).
959+
* Uses TelephonyManager.getSimOperator() directly.
960+
* Returns empty string if unavailable.
961+
*/
962+
override val mobileNetworkOperator: String
963+
get() = carrierTelephonyManager?.simOperator ?: ""
964+
898965
/** Check if location services are enabled */
899966
override fun getIsLocationEnabled(): Boolean {
900967
return try {

packages/react-native-nitro-device-info/ios/DeviceInfo.swift

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,73 @@ class DeviceInfo: HybridDeviceInfoSpec {
929929
return cachedCarrier
930930
}
931931

932+
// MARK: - Carrier Information (react-native-carrier-info parity)
933+
934+
/// Cached CTCarrier for carrier info APIs
935+
private var cachedCarrierObject: CTCarrier? {
936+
let networkInfo = CTTelephonyNetworkInfo()
937+
if let providers = networkInfo.serviceSubscriberCellularProviders {
938+
return providers.values.first
939+
}
940+
return nil
941+
}
942+
943+
/**
944+
* Check if carrier allows VoIP calls on its network
945+
*
946+
* Uses CTCarrier.allowsVOIP (deprecated but still functional on iOS 16+)
947+
* Returns true on Android (no equivalent API)
948+
*/
949+
var carrierAllowsVOIP: Bool {
950+
return cachedCarrierObject?.allowsVOIP ?? true
951+
}
952+
953+
/**
954+
* ISO 3166-1 country code for the carrier
955+
*
956+
* Returns the ISO country code (e.g., "US", "KR", "JP")
957+
* Returns empty string if unavailable
958+
*/
959+
var carrierIsoCountryCode: String {
960+
return cachedCarrierObject?.isoCountryCode ?? ""
961+
}
962+
963+
/**
964+
* Mobile Country Code (MCC)
965+
*
966+
* Returns 3-digit MCC per ITU-T E.212 (e.g., "310" for USA, "450" for Korea)
967+
* Returns empty string if unavailable
968+
*/
969+
var mobileCountryCode: String {
970+
return cachedCarrierObject?.mobileCountryCode ?? ""
971+
}
972+
973+
/**
974+
* Mobile Network Code (MNC)
975+
*
976+
* Returns 2 or 3-digit MNC (e.g., "260" for T-Mobile US)
977+
* Returns empty string if unavailable
978+
*/
979+
var mobileNetworkCode: String {
980+
return cachedCarrierObject?.mobileNetworkCode ?? ""
981+
}
982+
983+
/**
984+
* Mobile Network Operator (MCC + MNC combined)
985+
*
986+
* Returns combined MCC+MNC (e.g., "310260" for T-Mobile US)
987+
* Equivalent to mobileCountryCode + mobileNetworkCode
988+
* Returns empty string if unavailable
989+
*/
990+
var mobileNetworkOperator: String {
991+
let mcc = mobileCountryCode
992+
let mnc = mobileNetworkCode
993+
if mcc.isEmpty && mnc.isEmpty {
994+
return ""
995+
}
996+
return mcc + mnc
997+
}
998+
932999
/// Check if location services are enabled
9331000
func getIsLocationEnabled() -> Bool {
9341001
return CLLocationManager.locationServicesEnabled()

0 commit comments

Comments
 (0)