Ios开发常用权限汇总

主要总结下以下常用权限的获取及请求授权用法等(均不考虑iOS8以下系统): 网络权限 推送权限 定位权限 通讯录权限 相机权限 相册权限

网络权限

使用系统CoreTelephony库实现网络权限的获取及监听

  • 获取网络权限
     func getTelephonyAuthorization() {
          // 获取网络权限状态
          let cellularData = CTCellularData.init()
          switch cellularData.restrictedState {
              case .restricted:
                  print("restricted");
              case .notRestricted:
                  print("notRestricted");
              case .restrictedStateUnknown:
                  print("restrictedStateUnknown");
          }
      }
    
  • 请求(申请)网络权限 系统没有提供接口供开发者手动请求网络权限,iOS10及以上系统,应用首次请求网络时,系统会自动弹出权限选择框;而且一个应用只会弹出一次提示,提示过后就算卸载重装也不再提示; ps:首次请求时,如
     Alamofire.request("https://www.baidu.com")
    

    弹出权限提示框

hehe

  • iOS10及以上系统网络权限相关处理 iOS 10 之后首次安装的应用,请求网络时会弹出上面的提示框;在用户未选择前,所有网络请求都是失败的,这就会造成首页加载不出数据一片空白的情况;而且就算用户点击了允许,但在点击前的网络请求不会自动再次调用;对于这种情况,有几种解决办法:
    1. 封装网络框架,请求失败时,定时重新请求
    2. 提供数据空白页,空白页提供类似“重新加载”的按钮,允许及引导用户手动重新请求;
    3. 监听网络权限的变化,当监听到网络权限更改为允许后,重新请求;
       let cellularData = CTCellularData.init()
       func requestTelephonyAuthorization() {
         // 监听网络权限变化
         cellularData.cellularDataRestrictionDidUpdateNotifier = {state in
             switch state {
                 case .restricted:
                     print("restricted");
                 case .notRestricted:
                     print("notRestricted");
                 case .restrictedStateUnknown:
                     print("restrictedStateUnknown");
             }
         }
        }
      

      详细处理流程,可参考iOS 10 之 网络权限带来的坑

      推送权限

      推送相关API iOS10更新了,对应的权限API有所不同;

  • 获取推送权限 系统并没有提供获取推送权限状态的API,但可以通过NotificationSettings判断:
     func getNotificationAuthorization() {
          if #available(iOS 10.0, *) {
              UNUserNotificationCenter.current().getNotificationSettings { (settings) in
                  switch settings.authorizationStatus.rawValue {
                  case 0:
                      print("not authorized")
                  default:
                      print("authorized")
                  }
              }
          }else {
              guard let settings = UIApplication.shared.currentUserNotificationSettings else {
                  print("not settings");
                  return;
              }
              switch settings.types.rawValue {
              case 0:
                  print("not authorized")
              default:
                  print("authorized")
              }
          }
      }
    
  • 请求推送权限 iOS10之前系统,对于请求(申请)推送权限也没有具体的API;只有当应用设置NotificationSettings时,会自动请求推送权限并弹出提示框(提示框应用只会提示一次,不同于网络权限,应用卸载重装后,首次设置NotificationSettings时也会弹出提示框); iOS10及之后系统,同上面一样;但系统增加了请求推送权限的接口,可以手动调用接口来请求申请权限,对于手动请求的还可以监听到用户的选项(允许还是拒绝);手动请求权限,应用也只会首次时弹提示框;
    func requestNotificationAuthorization() {
          if #available(iOS 10.0, *) {
              let center = UNUserNotificationCenter.current()
              center.requestAuthorization(options: [.alert,.sound,.badge]) { (granted, error) in
                  if granted {
                      print("authorized");
                  }else {
                      print("not authorized");
                  }
              }
          } else {
              let setting = UIUserNotificationSettings.init(types: [.alert,.sound,.badge], categories: nil)
              UIApplication.shared.registerUserNotificationSettings(setting)
          }
      }
    

定位权限

定位权限有两种情况,一种是针对手机的(全部应用),一种是针对当前应用;两种情况都有对应接口获取权限状态;

  • 获取定位权限
     func getLocationAuthorization() {
          // 手机的定位权限
          if !CLLocationManager.locationServicesEnabled() {
              print("disenable")
              return;
          }
          // 应用的定位权限
          let status = CLLocationManager.authorizationStatus()
          switch status {
              case .authorizedAlways:
                  print("always")
              case .authorizedWhenInUse:
                  print("authorizedWhenInUse")
              case .denied:
                  print("denied")
              case .notDetermined:
                  print("notDetermined")
              case .restricted:
                  print("restricted")
          }
      }
    
  • 请求定位权限 使用相应接口定位时,会自动请求权限;也可以调用接口手动请求,应用只有首次使用时才会弹出权限提示框;与其他权限不同的是,手动请求定位权限是通过delegate回调的,在回调中可以监听并获取到用户的选项;
     let manager = CLLocationManager.init()
      func requestLocationAuthorization() {
          manager.delegate = self
          manager.requestAlwaysAuthorization()
          manager.requestWhenInUseAuthorization()
      }
        
      func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
          switch status {
          case .authorizedAlways:
              print("always")
          case .authorizedWhenInUse:
              print("authorizedWhenInUse")
          case .denied:
              print("denied")
          case .notDetermined:
              print("notDetermined")
          case .restricted:
              print("restricted")
          }
      }
    
  • 权限描述 为了让用户清楚了解申请权限的具体用途,iOS已强制开发者为某些权限在info.plist中添加对应的描述;该描述将显示在权限提示框上;这个描述一定要阐明权限的具体用途,比如该权限将用于什么功能之类的,否则app审核会被拒(亲身经历,血的教训);

key

定位权限描述的key有: NSLocationAlwaysAndWhenInUseUsageDescription, NSLocationWhenInUseUsageDescription

通讯录权限

通讯录相关API iOS9更新了,对应的权限API有所不同;

  • 获取通讯录权限
    func getContactAuthorization() {
          if #available(iOS 9.0, *) {
              let status = CNContactStore.authorizationStatus(for: .contacts)
              // ...
          }else {
              let status = ABAddressBookGetAuthorizationStatus()
              // ...
          }
      }
    
  • 请求通讯录权限 和上面权限类似;可以自动,也可以手动请求并监听权限
      func requestContactAuthorization() {
          if #available(iOS 9.0, *) {
              let contact = CNContactStore.init()
              contact.requestAccess(for: .contacts) { (granted, error) in
                  // ...
              }
          }else {
              let addressBook = ABAddressBookCreateWithOptions(nil, nil)
              ABAddressBookRequestAccessWithCompletion(addressBook as ABAddressBook) { (granted, error) in
                  // ...
              }
          }
      }
    
  • 权限描述 key:NSContactsUsageDescription

相机权限

  • 获取相机权限
      func getVideoAuthorization() {
          let videoAuthorStatus = AVCaptureDevice.authorizationStatus(for: .video)
          switch videoAuthorStatus {
              case .authorized:
                  print("authorized");
              case .denied:
                  print("denied");
              case .notDetermined:
                  print("notDetermined");
              case .restricted:
                  print("restricted");
          }
      }
    
  • 请求相机权限
      func requestVideoAuthorization() {
          AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted) in
              if granted {
                  print("authorized");
              }else {
                  print("not authorized");
              }
          })
      }
    
  • 权限描述 key:NSCameraUsageDescription

相册权限

访问系统相册,保存图片至手机相册均需要该权限;

  • 获取相册权限
      func getPhotoAuthorization() {
          let photoAuthorStatus = PHPhotoLibrary.authorizationStatus()
          switch photoAuthorStatus {
              case .authorized:
                  print("authorized");
              case .denied:
                  print("denied");
              case .notDetermined:
                  print("notDetermined");
              case .restricted:
                  print("restricted");
              }
      }
    
  • 请求相册权限
      func requestPhotoAuthorization() {
          PHPhotoLibrary.requestAuthorization { (status) in
              if status == PHAuthorizationStatus.authorized {
                  print("authorized");
              }else {
                  print("not authorized");
              }
          }
      }
    
  • 权限描述 key:NSPhotoLibraryUsageDescription

开发中使用场景

  • 在首次使用具体某些功能时(如拍照,读取照片),系统会自动弹出提示框,向用户申请对应权限;某些权限,开发者也可以手动调用接口来请求、向用户申请相应权限;具体是选择自动请求还是手动请求,可以视需求而定;对于不是频繁使用的功能,可以在使用该功能时再申请权限,也即让系统自动请求;而手动调用接口请求,主要作用是:可以提前申请权限,或者在应用启动后统一申请要用到的权限;
  • 需要用户授权的功能,有可能被用户拒绝授权;所以使用这些功能前要先获取对应的权限状态,如果权限是被拒绝的就需要进一步处理;一般的处理办法是,弹出提示框引导用户开启该权限,最好是提供一个按钮能直接跳转至系统设置界面;跳转至系统设置界面的代码:
    // iOS8及以上系统
    UIApplication.shared.openURL(NSURL.init(string: UIApplication.openSettingsURLString) as! URL)
    
  • 引导用户去设置界面开启权限时,我们希望能得到反馈(即用户是否真的去开启了权限),如果用户去设置界面开启了权限后,再重新实现具体功能;比如,使用拍照功能时,首先判断相机权限状态,获取的状态是拒绝的就弹出提示框引导用户去设置界面开启;用户开启权限后,应用再重新调用拍照功能,就不需要用户再多做一步操作了; 但用户是否在设置界面开启权限,我们是不得而知的;但可以通过其他方式实现:
    1. 开启定时器,每间隔一段时间重新获取权限状态;当权限状态为允许时,再做相关处理;
    2. 当用户切换至系统设置界面再回到当前应用时,当前应用状态肯定会经过BecomeActive这个状态,那么我们可以添加UIApplication.didBecomeActiveNotification通知监听这个状态,做相应处理;
      NotificationCenter.default.addObserver(self, selector: #selector(becomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
      

      以上权限中,通讯录权限、相册权限、相机权限当用户切换至系统设置界面更改后,应用将被kill

Written on March 24, 2019