iOS 16 CTCarrier deprecation

For iOS 16.X, CTCarrier will be deprecated. https://developer.apple.com/documentation/coretelephony/ctcarrier

①Could someone tell me why CTCarrier will be deprecated?

②What will be the correct way, going forward, to receive information regarding carrier information such as mobileCountryCode, mobileNetworkCode?

Post not yet marked as solved Up vote post of cf_cw Down vote post of cf_cw
17k views
  • We used to obtain operators through CTCarrier, but now ios16.4 CTCarrier only returns 65535. Since CTCarrier is Deprecated,Why is serviceSubscriberCellularProviders still returning "NSDictionary<NSString *, CTCarrier *>"? What should I use to replace it

Add a Comment

Replies

Note this annotation at the top of <CoreTelephonyCTCarrier.h>:

CORETELEPHONY_CLASS_DEPRECATED(4_0, 16_0, "Deprecated with no replacement")

I haven’t looked into this specifically but I suspect that is is a privacy thing. See my footnote at the bottom of this post.

What will be the correct way, going forward, to receive information regarding carrier information such as mobileCountryCode, mobileNetworkCode?

What are you using that info for?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • Hi Quinn,

    I am using this property to determine if current device can make phone calls. More precisely, to enable or disable a button to select a phone number, and then perform a call. Now that it's deprecated, what is the appropiate way to detect such scenario?

    Thank you for your help. Alex.

Add a Comment

Hi, I have the same question, looking for a replacement for CTCarrier. I am using mobileNetworkCode as a way to see if the iDevice can actually perform a call at this moment, since an iPhone could also be used without a SIM-card installed. I am using code that I picked up as a gist on Github, see below (part of a SwiftUI View). If you would have another way to check call capability without using CTCarrier, I would be much obliged.

                   Button (action: {
                        // check if device can perform phone call
                        // https://gist.github.com/krin-san/8f34206bc0e7c9fddcc9
                        var isCapableToCall: Bool = false
                        guard let url = URL(string: "tel:"+item.telephone) else {return}
                        if UIApplication.shared.canOpenURL(url) {
                            // Check if iOS Device supports phone calls
                            // User will get an alert error when they will try to make a phone call in airplane mode
                            if let subscribers = CTTelephonyNetworkInfo().serviceSubscriberCellularProviders {
                                for key in subscribers.keys {
                                    if ((subscribers[key]?.mobileNetworkCode?.isEmpty) == nil) {
                                        isCapableToCall = true
                                        break
                                    }
                                }
                            } else {
                                // Device cannot place a call at this time. SIM might be removed
                                isCapableToCall = false
                            }
                        } else {
                            // iOS Device is not capable for making calls
                            isCapableToCall = false
                        }
                        if isCapableToCall {
                                UIApplication.shared.open(url)
                        } else {
                            // if device cannot call, show a dialog with the phone number
                            showPhoneNumber.toggle()
                        }
                    }, label: {
                        VStack {
                            Image(systemName: "phone").font(.system(.title2))
                            Text(LocalizedStringKey("Call"))
                                .font(.caption2)
                                .padding(1)
                        }
                        .frame(width: 50, height: 45)
                    })

A phone call? Hmmm, using CT for that doesn’t seem like a great plan. It’s easy to imagine a world where tel URLs get handled by a VoIP app, completely unrelated to the device’s GSM state.

It’d be nice if canOpenURL(_:) were a bit smarter about this, returning false in the case that you’re trying to detect. Or perhaps we could add an API more specific to tel URLs. If you’d like to see such support added in the future, I encourage you to file an enhancement request describing your requirements.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

So true. I guess I'm growing old. Since the datastore only provides actual phone numbers, I had not thought of a VoIP app. So for a more general case than mine, you're spot on. I have now filed a Suggestion to make canOpenURL smarter. That would be a good spot for getting my way of using CTCarrier covered in a future iOS. Bug/suggestion number FB11678610 .

Add a Comment

@eskimo

There are a few things I would like to ask regarding this deprecation.

  1. I wonder why var serviceSubscriberCellularProviders: [String : CTCarrier]? { get } is not deprecated which has a returning type of CTCarrier and CTCarrier itself is deprecated. So what will happen exactly once CTCarrier gets removed ?

  2. What would happen if , for example CTCarrier gets removed in iOS 17, and user with iOS 17 installs our old app or has the previous version of the app that is using serviceSubscriberCellularProviders ?

  3. We would really need to keep using this CTCarrier class (we need the mobileCountryCode and mobileNetworkCode fields) as we need to identify mobile carrier used to connect to the internet, so we can call a carrier specific API.

Is there anything else we are able to use for this ?

Thank you in advance and I would appreciate any kind of additional information regarding this.

1. I wonder why serviceSubscriberCellularProviders is not deprecated which has a returning type of CTCarrier and CTCarrier itself is deprecated. So what will happen exactly once CTCarrier gets removed?

2. What would happen if, for example CTCarrier gets removed in iOS 17, and user with iOS 17 installs our old app or has the previous version of the app that is using serviceSubscriberCellularProviders?

Our usual pattern for removing an API is:

  1. Deprecate the API.

  2. Stub out the implementation. For example, in the UIDevice.name property, we have it return a dummy value. This may or may not be gated by a linked-on-or-later check or an entitlement.

  3. Remove the API from the SDK headers.

  4. Remove the API implementation entirely.

That last step usually only happens during architecture changes — for example, when moving from Intel and Apple silicon on the Mac — because otherwise it prevents apps with conditional code from launching.

As to how things will pan out in this specific case, I can’t predict the future (alas!) and so I’m not going to comment on that.

3. We would really need to keep using this CTCarrier class (we need the mobileCountryCode and mobileNetworkCode fields) as we need to identify mobile carrier used to connect to the internet, so we can call a carrier specific API.

If you have a hard dependency on these values I recommend that you:

  1. File a bug report with the details of this issue. Please post the bug number here, just for the record.

  2. Make sure that the carrier you’re working with understands this risk. They may want to make changes or raise this issue with their contacts at Apple.

Is there anything else we are able to use for this ?

No. That’s what Deprecated with no replacement means.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Add a Comment

There is a comment in the latest iOS 16.4 Beta 3 release notes that speak to this:

URL = https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-16_4-release-notes

Core Telephony Deprecations CTCarrier, a deprecated API, returns static values for apps that are built with the iOS 16.4 SDK or later. (76283818)

  • Thanks for the heads up.

Add a Comment

Financial institutions also use this API as a means to combat fraud. The alternative to deprecation could have been an entitlement request based on a genuine use case just certain Wifi APIs.

  • We have been using carrier countries to detect scammers and prevent fraud. Losing this is a huge **** to safety on Apple devices. I 100% agree that an entitlement request would have been a better way to do this. Apple should invest some more time looking into the rampant scamming going on and has the responsibility to help better protect their customers.

  • This is exactly the same issue we're facing now, too.

    Many fraud-preventing SDKs used by financial institutions rely on this data. This change impacts their capability to track fraudulent transactions on iOS directly, making the platform less secure to end users.

Add a Comment

Financial institutions also use this API as a means to combat fraud.

Are you building a product for a financial institution that does this? Or just raising this as a general concern?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • The product has been built and in use for many years now.

Add a Comment

Are you building a product for a financial institution that does this? Or just raising this as a general concern?

The product has been built and in use for many years now.

The product has been built and in use for many years now.

OK. In that case I think that it’s worth you following the advice from my earlier post. Better never than late late than never, right?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

We must somehow always have overlooked this depreciation notice (because it came as a surprise). The probable use case for many is; to preselect the country(code) if a phone number needs to be activated or targeted. And not have the users scroll though a list off all countries.

I might be missing something here but I would indeed suggest all that arrive here and have a good/valid/urgent use case to file a bug report as @eskimo suggested [ FB12130946 ]

  • To add it is the "without replacement" part that was overlooked. Not having a replacement makes this one unique and maybe a bit out of touch and unrealistic.

    Why only now; It has become necessity to deal with the deprecations once they actually arrive and normally one drops in the "replacement". Especially if one is running multiple projects for clients that need value driven updates. Looking at frameworks with plenty developers, those have many depreciation notices as well.

Add a Comment

Hey hey 👋

same as @spoxies, we use CTCarrier to detect the SIM's country code to preselect the correct country code for our phone numebr entry:

https://github.com/Blackjacx/Columbus/blob/dd328d6a66686e067da4990ab472fa14cf681eaa/Source/Classes/CountryPickerViewController.swift#L268-L281

I wonder how all the apps, that use phone numebr login, should do that from now on... I mean yes we could use the Locale information but that is not really accurate, right?

Any suggestions?

Thanks in advance!

Hi,

We are using CTTelephonyNetworkInfo.serviceSubscriberCellularProviders to list the active subscriptions on the device. Is there another way to fulfil this use case?

Thanks

ok, so this API is gone, but what is the reasoning for CTTelephonyNetworkInfo.serviceSubscriberCellularProviders to also always return an object and never update regardless of whether a SIM is actually inserted? Why aren't developers allowed to know whether a SIM is present at all?