前提
Xcode Version 12.4 (12D4e)で動作確認しています。
概要
iOSでCoreTelephonyを使って、今使っているキャリアが5Gかどうかを判別します。
また、その際の罠について紹介します。
結論
iOS 14.1以上で、5Gかどうかの判断をするようにしましょう。
今使っているキャリアを取得
まず、CTTelephonyNetworkInfoを生成します。
CTTelephonyNetworkInfoからserviceSubscriberCellularProviders を使って端末のキャリアを取得します。
keyとともに CTCarrier を取得できます。
let info = CTTelephonyNetworkInfo()
info.serviceSubscriberCellularProviders?.forEach({ (key, value) in
print(value.carrierName ?? "")
})
無線テクノロジーを取得
先ほど得たキーで、serviceCurrentRadioAccessTechnologyより無線のテクノロジーが何であるかを取得可能です。
CoreTelephonyのドキュメントに Radio Access Technology Constantsがあるので、switchを使って目的の無線テクノロジーを検出できます。
CTRadioAccessTechnologyNR,CTRadioAccessTechnologyNRNSAは5Gになります。
二つの違いはスタンドアローン型か非スタンドアローン型かの違いです。詳しくはWikipediaを貼っておきます。
https://ja.wikipedia.org/wiki/5G_NR#展開方式
let info = CTTelephonyNetworkInfo()
info.serviceSubscriberCellularProviders?.forEach({ (key, value) in
if let radioAccessTechnology = info.serviceCurrentRadioAccessTechnology?[key] {
switch radioAccessTechnology {
case CTRadioAccessTechnologyLTE:
print("これはLTEです")
case CTRadioAccessTechnologyNRNSA:
print("これは非スタンドアローンモード 5Gです")
case CTRadioAccessTechnologyNR:
print("スタンドアローンモード 5Gです")
default:
print(radioAccessTechnology)
}
}
})
iOS 13以下への対応
しかしながら、開発中のアプリがiOS13以降にも対応するとなると、このコードだとエラーが起きます。
'CTRadioAccessTechnologyNRNSA' is only available in iOS 14.0 or newer
ということなので、version checkのコードを追加します。
let info = CTTelephonyNetworkInfo()
info.serviceSubscriberCellularProviders?.forEach({ (key, value) in
if let radioAccessTechnology = info.serviceCurrentRadioAccessTechnology?[key] {
switch radioAccessTechnology {
case CTRadioAccessTechnologyLTE:
print("これはLTEです")
default:
if #available(iOS 14.0, *) {
switch radioAccessTechnology {
case CTRadioAccessTechnologyNRNSA:
print("これは非スタンドアローンモード 5Gです")
case CTRadioAccessTechnologyNR:
print("スタンドアローンモード 5Gです")
default:
print(radioAccessTechnology)
}
} else {
print(radioAccessTechnology)
}
}
}
})
ここから罠
実はこのコード、iOS 14.0系のOSで実行するとクラッシュします。
理由はCTRadioAccessTechnologyNRNSAとCTRadioAccessTechnologyNRの部分で、
実はこの二つの定数はiOS 14.1からのAPIであるとの記載がWebのドキュメントにあります。
しかしながら、Xcodeで定義にジャンプするとこれらのAPIは @available(iOS 14.0, *) でマークされています。
このため、対応OSと定義で不整合が起きて、iOS 14.0に本来無いAPIに触ろうとしてクラッシュするわけです。
対策
#available の部分を iOS 14.1に変更しましょう。
これで本来APIが使えるOSだけがAPIに触ることになります。
let info = CTTelephonyNetworkInfo()
info.serviceSubscriberCellularProviders?.forEach({ (key, value) in
if let radioAccessTechnology = info.serviceCurrentRadioAccessTechnology?[key] {
switch radioAccessTechnology {
case CTRadioAccessTechnologyLTE:
print("これはLTEです")
default:
if #available(iOS 14.1, *) {
switch radioAccessTechnology {
case CTRadioAccessTechnologyNRNSA:
print("これは非スタンドアローンモード 5Gです")
case CTRadioAccessTechnologyNR:
print("スタンドアローンモード 5Gです")
default:
print(radioAccessTechnology)
}
} else {
print(radioAccessTechnology)
}
}
}
})
ちなみに
Xcode Version 12.5 beta 3 (12E5244e)だと、この問題は解決されていて、CTRadioAccessTechnologyNRNSAとCTRadioAccessTechnologyNRは @available(iOS 14.1, *) でマークされています。
