1 import CoreTelephony
2 import ABI49_0_0ExpoModulesCore
3 
4 public class CellularModule: Module {
definitionnull5   public func definition() -> ModuleDefinition {
6     Name("ExpoCellular")
7 
8     Constants {
9       Self.getCurrentCellularInfo()
10     }
11 
12     AsyncFunction("getCellularGenerationAsync") { () -> Int in
13       Self.currentCellularGeneration().rawValue
14     }
15 
16     AsyncFunction("allowsVoipAsync") { () -> Bool? in
17       Self.currentCarrier()?.allowsVOIP
18     }
19 
20     AsyncFunction("getIsoCountryCodeAsync") { () -> String? in
21       Self.currentCarrier()?.isoCountryCode
22     }
23 
24     AsyncFunction("getCarrierNameAsync") { () -> String? in
25       Self.currentCarrier()?.carrierName
26     }
27 
28     AsyncFunction("getMobileCountryCodeAsync") { () -> String? in
29       Self.currentCarrier()?.mobileCountryCode
30     }
31 
32     AsyncFunction("getMobileNetworkCodeAsync") { () -> String? in
33       Self.currentCarrier()?.mobileNetworkCode
34     }
35   }
36 
37   // MARK: - internals
38 
39   // Keep this enum in sync with JavaScript
40   // Based on the EffectiveConnectionType enum described in the W3C Network Information API spec
41   // (https://wicg.github.io/netinfo/).
42   enum CellularGeneration: Int {
43     case unknown = 0
44     case cellular2G = 1
45     case cellular3G = 2
46     case cellular4G = 3
47     case cellular5G = 4
48   }
49 
currentCellularGenerationnull50   static func currentCellularGeneration() -> CellularGeneration {
51     let radioAccessTechnology = currentRadioAccessTechnology()
52 
53     switch radioAccessTechnology {
54     case CTRadioAccessTechnologyGPRS,
55          CTRadioAccessTechnologyEdge,
56          CTRadioAccessTechnologyCDMA1x:
57       return .cellular2G
58     case CTRadioAccessTechnologyWCDMA,
59          CTRadioAccessTechnologyHSDPA,
60          CTRadioAccessTechnologyHSUPA,
61          CTRadioAccessTechnologyCDMAEVDORev0,
62          CTRadioAccessTechnologyCDMAEVDORevA,
63          CTRadioAccessTechnologyCDMAEVDORevB,
64          CTRadioAccessTechnologyeHRPD:
65       return .cellular3G
66     case CTRadioAccessTechnologyLTE:
67       return .cellular4G
68     default:
69       if #available(iOS 14.1, *) {
70         if radioAccessTechnology == CTRadioAccessTechnologyNRNSA ||
71             radioAccessTechnology == CTRadioAccessTechnologyNR {
72           return .cellular5G
73         }
74       }
75       return .unknown
76     }
77   }
78 
getCurrentCellularInfonull79   static func getCurrentCellularInfo() -> [String: Any?] {
80     let carrier = Self.currentCarrier()
81     let generation = Self.currentCellularGeneration()
82 
83     return [
84       "allowsVoip": carrier?.allowsVOIP,
85       "carrier": carrier?.carrierName,
86       "isoCountryCode": carrier?.isoCountryCode,
87       "mobileCountryCode": carrier?.mobileCountryCode,
88       "mobileNetworkCode": carrier?.mobileNetworkCode,
89       "generation": generation.rawValue
90     ]
91   }
92 
currentRadioAccessTechnologynull93   static func currentRadioAccessTechnology() -> String? {
94     let netinfo = CTTelephonyNetworkInfo()
95 
96     if #available(iOS 12.0, *) {
97       return netinfo.serviceCurrentRadioAccessTechnology?.values.first
98     } else {
99       return netinfo.currentRadioAccessTechnology
100     }
101   }
102 
currentCarriernull103   static func currentCarrier() -> CTCarrier? {
104     let netinfo = CTTelephonyNetworkInfo()
105 
106     if #available(iOS 12.0, *), let providers = netinfo.serviceSubscriberCellularProviders {
107       for carrier in providers.values where carrier.carrierName != nil {
108         return carrier
109       }
110       return providers.values.first
111     }
112     return netinfo.subscriberCellularProvider
113   }
114 }
115