4

I have the following code:

let networkStatus = CTTelephonyNetworkInfo()

func getCellularInfo() {
    if #available(iOS 12.0, *) {
        var info = networkStatus.serviceSubscriberCellularProviders
        if let aKey = networkStatus.value(forKey: "serviceSubscriberCellularProvider") {
            print("aKey: \(aKey)")
        }
    }
}

This code retuns:

aKey: { 0000000100000001 = "CTCarrier (0x28282e610) {\n\tCarrier name: [Vodacom]\n\tMobile Country Code: [655]\n\tMobile Network Code:[01]\n\tISO Country Code:[za]\n\tAllows VOIP? [YES]\n}\n"; }

I am not familiar with this method, how do I obtain the values associated with the keys, for example \n\tMobile Country Code: [655]/n/

shawn.t
  • 105
  • 1
  • 9
  • Don't use `value(forKey:)`, prefers `object(forKey:)`. Also, as said by the doc `info` is `[String : CTCarrier]`, so you want the values of the dictionary (for instance, iterate the dictionary and get the carrier), and then `myCarrier.mobileCountryCode` – Larme Oct 30 '18 at 14:21
  • Why are you even using `value(forKey:)` for this? What's wrong with just directly accessing the value with `networkStatus.serviceSubscriberCellularProviders`, as you already did? – Alexander Oct 30 '18 at 15:18

3 Answers3

6

The property serviceSubscriberCellularProviders on CTTelephonyNetworkInfo returns a dictionary of CTCarrier objects keyed by String.

var serviceSubscriberCellularProviders: [String : CTCarrier]?

You can see that in your claimed output: CTCarrier (0x28282e610) {....

How you got that output is unclear as your posted code, while syntax correct, never uses the generated info dictionary variable.

So with correct code (assuming serviceSubscriberCellularProvider is the key):

let networkStatus = CTTelephonyNetworkInfo()
if let info = networkStatus.serviceSubscriberCellularProviders, 
   let carrier = info["serviceSubscriberCellularProvider"] {
    //work with carrier object
    print("MNC = \(carrier.mobileNetworkCode)")
}

But that doesn't seem to work on a single SIM iPhone 7 running iOS 12.0.1. serviceSubscriberCellularProviders is nil. Possibly the newer phones with dual-SIM hardware will react differently.

The deprecated property still works however.

let networkStatus = CTTelephonyNetworkInfo()
if let carrier = networkStatus.subscriberCellularProvider {
    print("MNC = \(carrier.mobileNetworkCode ?? "NO CODE")")
}
Warren Burton
  • 17,451
  • 3
  • 53
  • 73
  • Tried it, CTCarrier returns nil when using the properties. – shawn.t Oct 30 '18 at 14:31
  • Updated the answer to include the conditional cast to `CTCarrier` . Any joy? – Warren Burton Oct 30 '18 at 14:36
  • `let ctCarrier = CTCarrier() func getMNC() -> String { if let mnc = ctCarrier.mobileNetworkCode { return mnc } return "nil found when using MNC" }` Returns nil – shawn.t Oct 30 '18 at 14:36
  • That won't work , you are creating an empty `CTCarrier` object. – Warren Burton Oct 30 '18 at 14:37
  • I did that in the edit previously. I have made the code even more explicit now. – Warren Burton Oct 30 '18 at 14:46
  • I was referring to the subject where you pointed out that I'm creating an empty CTCarrier object. – shawn.t Oct 31 '18 at 09:05
  • The solution doesn't seem to be working. I'm still getting nil. – shawn.t Oct 31 '18 at 09:47
  • I have rewritten the answer. Your supplied code could never work. – Warren Burton Oct 31 '18 at 11:14
  • Solved! Been using an iPhone 7+ for Development. – shawn.t Oct 31 '18 at 13:22
  • This is a bad answer. Your assumption of using "serviceSubscriberCellularProvider" as a key is invalid, even in OPs original question you can see the key is "0000000100000001", which doesn't make much sense to anyone using the new API. – Claus Jørgensen Nov 06 '18 at 15:34
  • @ClausJørgensen I have no idea what the key is in reality. The API doesnt work for me on device and the OP's original code was bogus. I have no idea where they got the log output either. The best strategy will be to iterate through the values ignoring keys. "0000000100000001" seems to be maybe an Int. – Warren Burton Nov 06 '18 at 17:24
  • @WarrenBurton yeah, the API seems incomplete. It exists to support dual sim, so it would make sense to use the "active" SIM or something, but Apple doesn't seem to provide that API yet. – Claus Jørgensen Nov 07 '18 at 09:18
2

my two cents for iOS 13 / swift 5.1

class func getTelephonyInfo()->String?{
    let networkInfo = CTTelephonyNetworkInfo()

    let currCarrierType: String?
    if #available(iOS 12.0, *) {

        let serviceSubscriberCellularProviders = networkInfo.serviceSubscriberCellularProviders

        // get curr value:
        guard let dict = networkInfo.serviceCurrentRadioAccessTechnology else{
            return nil
        }
        // as apple states
        // https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo/3024510-servicecurrentradioaccesstechnol
        // 1st value is our string:
        let key = dict.keys.first! // Apple assures is present...

        // use it on previous dict:
        let carrierType = dict[key]

        // to compare:
        guard let carrierType_OLD = networkInfo.currentRadioAccessTechnology else {
            return nil
        }
        currCarrierType = carrierType

    } else {
        // Fall back to pre iOS12
        guard let carrierType = networkInfo.currentRadioAccessTechnology else {
            return nil
        }
        currCarrierType = carrierType
    }


    switch currCarrierType{
    case CTRadioAccessTechnologyGPRS:
        return "2G" + " (GPRS)"

    case CTRadioAccessTechnologyEdge:
        return "2G" + " (Edge)"

    case CTRadioAccessTechnologyCDMA1x:
        return "2G" + " (CDMA1x)"

    case CTRadioAccessTechnologyWCDMA:
        return "3G" + " (WCDMA)"

    case CTRadioAccessTechnologyHSDPA:
        return "3G" + " (HSDPA)"

    case CTRadioAccessTechnologyHSUPA:
        return "3G" + " (HSUPA)"

    case CTRadioAccessTechnologyCDMAEVDORev0:
        return "3G" + " (CDMAEVDORev0)"

    case CTRadioAccessTechnologyCDMAEVDORevA:
        return "3G" + " (CDMAEVDORevA)"

    case CTRadioAccessTechnologyCDMAEVDORevB:
        return "3G" + " (CDMAEVDORevB)"

    case CTRadioAccessTechnologyeHRPD:
        return "3G" + " (eHRPD)"

    case CTRadioAccessTechnologyLTE:
        return "4G" + " (LTE)"

    default:
        break;
    }

    return "newer type!"
}
ingconti
  • 10,876
  • 3
  • 61
  • 48
  • 1
    Apple does not assure that the dictionary returned by `serviceCurrentRadioAccessTechnology` is not empty. The proposed code will actually crash if you run it on an iPhone without a SIM card, because it returns an empty dictionary (`[:]`). – elitalon Dec 31 '20 at 08:59
  • you cane right. this is only a code sample with some tests against nils and similar. can be refined. – ingconti Jan 01 '21 at 09:20
0

Swift 5 / iOS 15.5 Handling Dual Sim

import CoreTelephony 

let networkStatus = CTTelephonyNetworkInfo()
if let info = networkStatus.serviceSubscriberCellularProviders, let carrier1 = info["0000000100000001"], let carrier2 = info["0000000100000002"] {
   print(carrier1.mobileCountryCode)
   print(carrier1.isoCountryCode)
   print(carrier2.mobileCountryCode)
   print(carrier2.isoCountryCode)
}
pawisoon
  • 1,427
  • 1
  • 15
  • 20