UIFeebackGeneratorは実行してもサポートしてない端末だと何も反応しないだけなので、特に端末のサポートを確認する必要はない。
だが、作ったアプリで設定画面からHaptic Feedbackをオン/オフできるようにした際に、混乱を避けるために非対応端末ではHaptic Feedbackの設定項目を非表示にしたかった。
Haptic Feedbackの対応状況なんて簡単に取得できると思ったのに、できなかったのでその方法をいくつかここに書く。
プライベート変数を使う
UIDeviceにはAppleが一般の開発者が利用できるようにしてないだけで、Haptic Feedbackに対応しているかを格納している変数が存在します。
UIDevice.current.value(forKey: "_feedbackSupportLevel") as? Int ?? 0
で取得できます。
Haptic Feedbackをサポートしていない端末だと0
iPhone6/6+の第1世代Taptic Engineに対応している端末だと1
iPhone7/7+以降の第2世代Taptic Engineに対応している端末だと2
という感じで整数の値が返ってきます。
問題点
これは便利なのですが、プライベート変数を利用しているのでこれを使ったアプリをAppStoreで公開しようとするとリジェクトされる可能性があります。
自分が使うだけのアプリならいいですけど、公開しているアプリでの使用は避けた方がいいと思います。
参考
端末のモデル名から判別する
Taptic Engineを搭載している端末は現状そこまで多くはありません。モデル名から判別することは可能でしょう。
func supportHapticFeedback() -> Bool {
// モデル名取得
var systemInfo = utsname()
uname(&systemInfo)
let mirror = Mirror(reflecting: systemInfo.machine)
var identifier = ""
for child in mirror.children {
if let value = child.value as? Int8, value != 0 {
identifier += String(UnicodeScalar(UInt8(value)))
}
}
// モデル名取得(ここまで)
// iPhone以外は非対応
if !identifier.hasPrefix("iPhone") {
return false
}
// モデル名の数字の部分だけ取り出す
let n = identifier.compactMap({ Int("\($0)") }).reduce(0, { $0 * 10 + $1 })
// iPhone8,1(6s)以降で、iPhone8,3 or 8,4(SE)でなければtrue
let list: Set<Int> = [83, 84]
return n > 80 && !list.contains(n)
}
問題点
新しい端末に対応できないので、新型のiPhoneが出るとこのコードでは判別できなくなる可能性があります。
また、今後Taptic Engine未搭載の新型iPhoneが出た場合、条件分岐がどんどん複雑になって管理しきれなくなる可能性もあります。
参考
あとがき
ちなみに、3D Touch対応機器にはTaptic Engineが搭載されているので、3D Touchの対応状況で確認するというのも考えたのですが、3D Touchは設定のアクセシビリティでオン/オフできるので判断には向かないと思い除外しました。
Haptic Feedback対応をチェックする機会は少ないと思いますが、ご参考までに