iOS info.plist应用权限配置

iOS APP审核比较严格,十分注重保护用户隐私。没有用户对APP授权,很多涉及数据采集的功能都无法使用。这里记录一些常用的权限配置及权限状态检查,后面会陆续补充。

一、常见隐私权限
1.基本格式 Privacy - xxxx :详细描述,如图:
样例一.png
ps:详细描述要写的与具体功能相关,否则APP审核可能会被打回。
2.隐私权限清单
Privacy - Camera Usage Description : 使用相机(拍照或录制)
Privacy - Face ID Usage Description : 使用FaceID
Privacy - NFC Scan Usage Description : 使用NFC扫描
Privacy - Microphone Usage Description :使用麦克风(录音)
Privacy - Bluetooth Always Usage Description :使用手机蓝牙
//定位
Privacy - Location When In Use Usage Description : APP使用期间获取定位信息(仅限应用在前台)
Privacy - Location Always and When In Use Usage Description :允许一直获取定位信息(包括前台和后台)
//图库
Privacy - Photo Library Usage Description :允许从图库读取图片或视频
Privacy - Photo Library Additions Usage Description :向图库添加图片或视频
二、检查权限状态,及主动申请
这一部分是最基本的容错,调用方法前去获取设备硬件状态或权限是否授权。进而去规避一些由于用户没有授权权限,直接调用对应方法而导致的崩溃。

1.相机
这里用到的是AVCaptureDevice来检查权限状态,后续会添加使用其他方法状态获取的方式。

    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.麦克风
同相机获取权限状态的方式,后续也会添加。

    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权限在iOS14.0进行了细化:
a)获取图库读写权限


        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.蓝牙

  //蓝牙状态获取是通过delegate方法centralManagerDidUpdateState来实现的
  func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .resetting:
            print("服务连接中断,正在重连")
        case .unsupported:
            print("设备不支持")
        case .unauthorized:
            if #available(iOS 13.0, *) {
                switch central.authorization {
                case .restricted:
                    print("设备蓝牙有问题,被限制使用")
                case .denied:
                    print("被用户拒绝了")
                default:
                    print("啥也不是~~~~~")
                }
            } else {
                print("用户未授权")
            }
        case .poweredOff:
            print("蓝牙未打开")
        case .poweredOn:
            print("蓝牙已打开")
            
        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://根据需求二选一
//            locationManager.requestAlwaysAuthorization()
            locationManager.requestWhenInUseAuthorization()
            
        case .restricted:
            print("The user authorized this app is restricted.")

        default:
            fatalError()
        }
    }

6.NFC
要使用NFC功能开发需要在证书中添加NFC开发选项,配置证书后然后在项目中添加Capability。


NFC Capability配置.png

获取状态是否可用比较简单,内部封装好的api直接调用即可。

//MARK: NFC相关
import CoreNFC
extension ViewController{
    func checkNFCReaderAvailable() -> Bool{
       return NFCNDEFReaderSession.readingAvailable
    }
}

7.FaceID
请求设备本地解锁认证(密码,faceID,TouchID),LAPolicy有两种枚举类型,deviceOwnerAuthenticationWithBiometrics仅调用设备设置的touchid或faceID进行认证,deviceOwnerAuthentication会根据设备设置的解锁方式进行请求,默认是设备密码认证,即使在没有设置生物学识别信息(指纹、面部特征)的情况下也可以使用

import LocalAuthentication
var context = LAContext()
extension ViewController{

    func requetAuthor(){
        /*
         canEvaluatePolicy()方法用来检查认证方式是否可用,也可用来标记状态
         evaluatePolicy()方法用来进行认证方法调用
        */
            context = LAContext()
            context.localizedCancelTitle = "设置title"

            var error: NSError?
            if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
                let reason = "设置具体描述"
                context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason ) { success, error in
                    if success {
                        DispatchQueue.main.async { [unowned self] in
                           print("认证成功")
                        }

                    } else {
                        print(error?.localizedDescription ?? "认证失败")
                    }
                }
            } else {
                print(error?.localizedDescription ?? "无法调用系统认证方式")
            }
        }
}

8.消息通知
检查消息通知状态

  func checkNotificationAvailable(){
        if #available(iOS 10, *) {
            UNUserNotificationCenter.current().getNotificationSettings { (settings) in
                print(settings.authorizationStatus)
                switch settings.authorizationStatus{
                case .authorized:
                    print("已授权")
                case .denied:
                    print("用户拒绝消息通知")
                case .notDetermined:
                    print("未确定消息权限")
                //这两个是新的,没有做深入探究
                case .ephemeral:
                    print("ephemeral")
                case .provisional:
                    print("provisional")

                default:
                    break
                }
            }
        }else{
            let isRegistered = UIApplication.shared.isRegisteredForRemoteNotifications
            print(isRegistered)
        }
    }
附:iOS 网络通信配置

iOS 9.0 以后APP网络请求需要在info.plist中配置NSAppTransportSecurity,具体配置如下图:
网络通信配置2.png
Apple官方文档:ProtectedResources
Demo:Demo链接
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容