iOS APP審核比較嚴(yán)格阵难,十分注重保護(hù)用戶隱私岳枷。沒有用戶對APP授權(quán),很多涉及數(shù)據(jù)采集的功能都無法使用。這里記錄一些常用的權(quán)限配置及權(quán)限狀態(tài)檢查嫩舟,后面會陸續(xù)補(bǔ)充付呕。
一箱熬、常見隱私權(quán)限
1.基本格式 Privacy - xxxx :詳細(xì)描述摹闽,如圖:
樣例一.png
ps:詳細(xì)描述要寫的與具體功能相關(guān)亚再,否則APP審核可能會被打回误堡。
2.隱私權(quán)限清單
Privacy - Camera Usage Description : 使用相機(jī)(拍照或錄制)
Privacy - Face ID Usage Description : 使用FaceID
Privacy - NFC Scan Usage Description : 使用NFC掃描
Privacy - Microphone Usage Description :使用麥克風(fēng)(錄音)
Privacy - Bluetooth Always Usage Description :使用手機(jī)藍(lán)牙
//定位
Privacy - Location When In Use Usage Description : APP使用期間獲取定位信息(僅限應(yīng)用在前臺)
Privacy - Location Always and When In Use Usage Description :允許一直獲取定位信息(包括前臺和后臺)
//圖庫
Privacy - Photo Library Usage Description :允許從圖庫讀取圖片或視頻
Privacy - Photo Library Additions Usage Description :向圖庫添加圖片或視頻
二豆茫、檢查權(quán)限狀態(tài)伸蚯,及主動申請
這一部分是最基本的容錯(cuò)撬码,調(diào)用方法前去獲取設(shè)備硬件狀態(tài)或權(quán)限是否授權(quán)维蒙。進(jìn)而去規(guī)避一些由于用戶沒有授權(quán)權(quán)限掰吕,直接調(diào)用對應(yīng)方法而導(dǎo)致的崩潰。
1.相機(jī)
這里用到的是AVCaptureDevice來檢查權(quán)限狀態(tài)颅痊,后續(xù)會添加使用其他方法狀態(tài)獲取的方式殖熟。
private func isPrepareOfAVCaptureVideoDevice(_ completionHandler: @escaping (Bool) -> Void) {
let videoStatus = AVCaptureDevice.authorizationStatus(for: .video)
if videoStatus == .notDetermined{
AVCaptureDevice.requestAccess(for: .video) {
completionHandler($0)
}
return
}
completionHandler(videoStatus == .authorized)
}
2.麥克風(fēng)
同相機(jī)獲取權(quán)限狀態(tài)的方式,后續(xù)也會添加斑响。
private func isPrepareOfAVCaptureAudioDevice(_ completionHandler: @escaping (Bool) -> Void) {
let audioStatus = AVCaptureDevice.authorizationStatus(for: .audio)
if audioStatus == .notDetermined {
AVCaptureDevice.requestAccess(for: .audio) {
completionHandler($0)
}
return
}
completionHandler(audioStatus == .authorized)
}
3.圖庫
PhotoLibrary權(quán)限在iOS14.0進(jìn)行了細(xì)化:
a)獲取圖庫讀寫權(quán)限
if #available(iOS 14, *) {
let readWriteStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
print(readWriteStatus)
PHPhotoLibrary.requestAuthorization(for: .readWrite) { (status) in
self.handleRequestStatus(status: status)
}
} else {
let readWriteStatus = PHPhotoLibrary.authorizationStatus()
print(readWriteStatus)
PHPhotoLibrary.requestAuthorization { (status) in
self.handleRequestStatus(status: status)
}
}
}
func handleRequestStatus(status:PHAuthorizationStatus){
switch status {
case .notDetermined:
print("The user hasn't determined this app's access.")
case .restricted:
print("The system restricted this app's access.")
case .denied:
print("The user explicitly denied this app's access.")
case .authorized:
print("The user authorized this app to access Photos data.")
case .limited:
print("The user authorized this app for limited Photos access.")
@unknown default:
fatalError()
}
}
b)僅向圖庫添加菱属,為了對稱添加了iOS14版本以下的
func checkPhotosLibraryAddtionStatus(){
if #available(iOS 14, *) {
let readWriteStatus = PHPhotoLibrary.authorizationStatus(for: .addOnly)
print(readWriteStatus)
PHPhotoLibrary.requestAuthorization(for: .addOnly) { [self] (status) in
handleRequestStatus(status: status)
}
} else {
let readWriteStatus = PHPhotoLibrary.authorizationStatus()
print(readWriteStatus)
PHPhotoLibrary.requestAuthorization { (status) in
self.handleRequestStatus(status: status)
}
}
}
func handleRequestStatus(status:PHAuthorizationStatus){
switch status {
case .notDetermined:
print("The user hasn't determined this app's access.")
case .restricted:
print("The system restricted this app's access.")
case .denied:
print("The user explicitly denied this app's access.")
case .authorized:
print("The user authorized this app to access Photos data.")
case .limited:
print("The user authorized this app for limited Photos access.")
@unknown default:
fatalError()
}
}
4.藍(lán)牙
//藍(lán)牙狀態(tài)獲取是通過delegate方法centralManagerDidUpdateState來實(shí)現(xiàn)的
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .resetting:
print("服務(wù)連接中斷,正在重連")
case .unsupported:
print("設(shè)備不支持")
case .unauthorized:
if #available(iOS 13.0, *) {
switch central.authorization {
case .restricted:
print("設(shè)備藍(lán)牙有問題舰罚,被限制使用")
case .denied:
print("被用戶拒絕了")
default:
print("啥也不是~~~~~")
}
} else {
print("用戶未授權(quán)")
}
case .poweredOff:
print("藍(lán)牙未打開")
case .poweredOn:
print("藍(lán)牙已打開")
default:
print("啥也不是~~~~~")
}
5.定位
func checkLocationStatus(){
let locationManager = CLLocationManager()
if #available(iOS 14.0, *) {
let status = locationManager.authorizationStatus
self.requestLocationAuthor(status: status)
} else {
let status = CLLocationManager.authorizationStatus()
self.requestLocationAuthor(status: status)
}
}
func requestLocationAuthor(status:CLAuthorizationStatus){
let locationManager = CLLocationManager()
switch status {
case .authorizedAlways:
print("The user authorized this app is authorizedAlways.")
case .authorizedWhenInUse:
print("The user authorized this app is authorizedWhenInUse.")
case .denied:
print("The user authorized this app is denied.")
case .notDetermined://根據(jù)需求二選一
// locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
case .restricted:
print("The user authorized this app is restricted.")
default:
fatalError()
}
}
6.NFC
要使用NFC功能開發(fā)需要在證書中添加NFC開發(fā)選項(xiàng)纽门,配置證書后然后在項(xiàng)目中添加Capability。
獲取狀態(tài)是否可用比較簡單营罢,內(nèi)部封裝好的api直接調(diào)用即可赏陵。
//MARK: NFC相關(guān)
import CoreNFC
extension ViewController{
func checkNFCReaderAvailable() -> Bool{
return NFCNDEFReaderSession.readingAvailable
}
}
7.FaceID
請求設(shè)備本地解鎖認(rèn)證(密碼,faceID饲漾,TouchID)蝙搔,LAPolicy有兩種枚舉類型,deviceOwnerAuthenticationWithBiometrics僅調(diào)用設(shè)備設(shè)置的touchid或faceID進(jìn)行認(rèn)證考传,deviceOwnerAuthentication會根據(jù)設(shè)備設(shè)置的解鎖方式進(jìn)行請求吃型,默認(rèn)是設(shè)備密碼認(rèn)證,即使在沒有設(shè)置生物學(xué)識別信息(指紋伙菊、面部特征)的情況下也可以使用
import LocalAuthentication
var context = LAContext()
extension ViewController{
func requetAuthor(){
/*
canEvaluatePolicy()方法用來檢查認(rèn)證方式是否可用败玉,也可用來標(biāo)記狀態(tài)
evaluatePolicy()方法用來進(jìn)行認(rèn)證方法調(diào)用
*/
context = LAContext()
context.localizedCancelTitle = "設(shè)置title"
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "設(shè)置具體描述"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason ) { success, error in
if success {
DispatchQueue.main.async { [unowned self] in
print("認(rèn)證成功")
}
} else {
print(error?.localizedDescription ?? "認(rèn)證失敗")
}
}
} else {
print(error?.localizedDescription ?? "無法調(diào)用系統(tǒng)認(rèn)證方式")
}
}
}
8.消息通知
檢查消息通知狀態(tài)
func checkNotificationAvailable(){
if #available(iOS 10, *) {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print(settings.authorizationStatus)
switch settings.authorizationStatus{
case .authorized:
print("已授權(quán)")
case .denied:
print("用戶拒絕消息通知")
case .notDetermined:
print("未確定消息權(quán)限")
//這兩個(gè)是新的,沒有做深入探究
case .ephemeral:
print("ephemeral")
case .provisional:
print("provisional")
default:
break
}
}
}else{
let isRegistered = UIApplication.shared.isRegisteredForRemoteNotifications
print(isRegistered)
}
}