jsdw_ios/QuickLocation/Manager/App/Authorize.swift

406 lines
14 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Authorize.swift
// DLSDK
//
// Created by osell on 2023/8/3.
//
import UIKit
import CoreLocation
import Photos
import AVFoundation
import UserNotifications
import AdSupport
import AppTrackingTransparency
import URLNavigator
// MARK: - AuthorizeType
///
@objc(DLAuthorizeType)
public enum AuthorizeType: Int {
/// 使Info.plistNSLocationWhenInUseUsageDescription
case locationWhenInUse = 1
/// Info.plistNSLocationAlwaysUsageDescriptionNSLocationAlwaysAndWhenInUseUsageDescription
case locationAlways = 2
/// MicrophoneInfo.plistNSMicrophoneUsageDescription
case microphone = 3
/// Info.plistNSPhotoLibraryUsageDescription
case photoLibrary = 4
/// Info.plistNSCameraUsageDescription
case camera = 5
/// ContactsInfo.plistNSContactsUsageDescription
case contacts = 6
/// CalendarInfo.plistNSCalendarsUsageDescription
case calendars = 7
/// CalendarInfo.plistNSRemindersUsageDescription
case reminders = 8
/// AppleMusicInfo.plistNSAppleMusicUsageDescription
case appleMusic = 9
/// Push NotificationsBackground ModesRemote notifications
case notifications = 10
/// 广TrackingInfo.plistNSUserTrackingUsageDescription
case tracking = 11
}
// MARK: - AuthorizeStatus
///
@objc(DLAuthorizeStatus)
public enum AuthorizeStatus: Int {
///
case notDetermined = 0
///
case restricted = 1
///
case denied = 2
///
case authorized = 3
}
// MARK: - AuthorizeProtocol
///
@objc(DLAuthorizeProtocol)
public protocol AuthorizeProtocol {
/// 线
func authorizeStatus() -> AuthorizeStatus
/// 线
func authorize(_ completion: ((AuthorizeStatus) -> Void)?)
/// 线线
@objc optional func authorizeStatus(_ completion: ((AuthorizeStatus) -> Void)?)
}
// MARK: - AuthorizeManager
/// ipaInfo.plist
///
@objc(DLAuthorizeManager)
@objcMembers public class AuthorizeManager: NSObject {
private static var managers: [AuthorizeType: AuthorizeProtocol] = [:]
private static var blocks: [AuthorizeType: () -> AuthorizeProtocol] = [:]
/// nil
public static func manager(type: AuthorizeType) -> AuthorizeProtocol? {
if let manager = managers[type] { return manager }
guard let manager = factory(type: type) else { return nil }
managers[type] = manager
return manager
}
///
public static func registerAuthorize(_ type: AuthorizeType, withBlock block: @escaping () -> AuthorizeProtocol) {
blocks[type] = block
}
private static func factory(type: AuthorizeType) -> AuthorizeProtocol? {
if let block = blocks[type] {
return block()
}
switch type {
case .locationWhenInUse:
return AuthorizeLocation(isAlways: false)
case .locationAlways:
return AuthorizeLocation(isAlways: true)
case .photoLibrary:
return AuthorizePhotoLibrary()
case .camera:
return AuthorizeCamera()
case .notifications:
return AuthorizeNotifications()
case .microphone:
return AuthorizeMicrophone()
case .tracking:
return AuthorizeTracking()
default:
return nil
}
}
static func openAppSetting(title: String, message: String) {
let alertVC = UIAlertController.init(title: title,
message: message,
preferredStyle: .alert)
let cancelAction = UIAlertAction.init(title: "取消", style: .cancel)
let setAction = UIAlertAction.init(title: "去设置", style: .default) { action in
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsURL) {
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
}
}
alertVC.addAction(cancelAction)
alertVC.addAction(setAction)
UIViewController.topMost?.present(alertVC, animated: true, completion: nil)
}
}
// MARK: - AuthorizeLocation
///
private class AuthorizeLocation: NSObject, AuthorizeProtocol, CLLocationManagerDelegate {
private lazy var locationManager: CLLocationManager = {
let result = CLLocationManager()
result.delegate = self
return result
}()
private var completionBlock: ((AuthorizeStatus) -> Void)?
private var changeIgnored: Bool = false
private var isAlways: Bool = false
init(isAlways: Bool) {
super.init()
self.isAlways = isAlways
}
func authorizeStatus() -> AuthorizeStatus {
// Denied[CLLocationManager locationServicesEnabled]
let status = CLLocationManager.authorizationStatus()
switch status {
case .restricted:
return .restricted
case .denied:
return .denied
case .authorizedAlways:
return .authorized
case .authorizedWhenInUse:
if isAlways {
let isAuthorized = UserDefaults.standard.object(forKey: "DLAuthorizeLocation")
return isAuthorized != nil ? .denied : .notDetermined
} else {
return .authorized
}
default:
return .notDetermined
}
}
func authorize(_ completion: ((AuthorizeStatus) -> Void)?) {
completionBlock = completion
if isAlways {
locationManager.requestAlwaysAuthorization()
//
UserDefaults.standard.set(NSNumber(value: 1), forKey: "DLAuthorizeLocation")
UserDefaults.standard.synchronize()
} else {
locationManager.requestWhenInUseAuthorization()
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// alwaysWhenInUse
if isAlways && !changeIgnored {
if status == .notDetermined || status == .authorizedWhenInUse {
changeIgnored = true
return
}
}
// 线
if completionBlock != nil {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.completionBlock?(self.authorizeStatus())
self.completionBlock = nil
}
}
}
}
// MARK: - AuthorizePhotoLibrary
///
private class AuthorizePhotoLibrary: NSObject, AuthorizeProtocol {
func authorizeStatus() -> AuthorizeStatus {
let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .restricted:
return .restricted
case .denied:
return .denied
case .authorized:
return .authorized
default:
return .notDetermined
}
}
func authorize(_ completion: ((AuthorizeStatus) -> Void)?) {
PHPhotoLibrary.requestAuthorization { status in
if completion != nil {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
completion?(self.authorizeStatus())
}
}
}
}
}
// MARK: - AuthorizeCamera
///
private class AuthorizeCamera: NSObject, AuthorizeProtocol {
func authorizeStatus() -> AuthorizeStatus {
//
let mediaType = AVMediaType.video
guard let device = AVCaptureDevice.default(for: mediaType) else { return .restricted }
if !device.hasMediaType(mediaType) { return .restricted }
let status = AVCaptureDevice.authorizationStatus(for: mediaType)
switch status {
case .restricted:
return .restricted
case .denied:
return .denied
case .authorized:
return .authorized
default:
return .notDetermined
}
}
func authorize(_ completion: ((AuthorizeStatus) -> Void)?) {
AVCaptureDevice.requestAccess(for: .video) { granted in
if completion != nil {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
completion?(self.authorizeStatus())
}
}
}
}
}
// MARK: - AuthorizeNotifications
///
private class AuthorizeNotifications: NSObject, AuthorizeProtocol {
func authorizeStatus() -> AuthorizeStatus {
var status: AuthorizeStatus = .notDetermined
// 使线
let semaphore = DispatchSemaphore(value: 0)
UNUserNotificationCenter.current().getNotificationSettings { settings in
switch settings.authorizationStatus {
case .denied:
status = .denied
case .authorized:
status = .authorized
case .provisional:
status = .authorized
default:
status = .notDetermined
}
semaphore.signal()
}
semaphore.wait()
return status
}
func authorizeStatus(_ completion: ((AuthorizeStatus) -> Void)?) {
UNUserNotificationCenter.current().getNotificationSettings { settings in
var status: AuthorizeStatus = .notDetermined
switch settings.authorizationStatus {
case .denied:
status = .denied
case .authorized:
status = .authorized
case .provisional:
status = .authorized
default:
status = .notDetermined
}
if completion != nil {
DispatchQueue.main.async {
completion?(status)
}
}
}
}
func authorize(_ completion: ((AuthorizeStatus) -> Void)?) {
let options: UNAuthorizationOptions = [.badge, .sound, .alert]
UNUserNotificationCenter.current().requestAuthorization(options: options) { granted, error in
let status: AuthorizeStatus = granted ? .authorized : .denied
if completion != nil {
DispatchQueue.main.async {
completion?(status)
}
}
}
UIApplication.shared.registerForRemoteNotifications()
}
}
// MARK: - AuthorizeMicrophone
///
private class AuthorizeMicrophone: NSObject, AuthorizeProtocol {
func authorizeStatus() -> AuthorizeStatus {
let status = AVAudioSession.sharedInstance().recordPermission
switch status {
case .denied:
return .denied
case .granted:
return .authorized
default:
return .notDetermined
}
}
func authorize(_ completion: ((AuthorizeStatus) -> Void)?) {
AVAudioSession.sharedInstance().requestRecordPermission { granted in
let status: AuthorizeStatus = granted ? .authorized : .denied
if completion != nil {
DispatchQueue.main.async {
completion?(status)
}
}
}
}
}
// MARK: - AuthorizeTracking
/// IDFAiOS14+使AppTrackingTransparency使AdSupport
class AuthorizeTracking: NSObject, AuthorizeProtocol {
func authorizeStatus() -> AuthorizeStatus {
if #available(iOS 14.0, *) {
let status = ATTrackingManager.trackingAuthorizationStatus
switch status {
case .restricted:
return .restricted
case .denied:
return .denied
case .authorized:
return .authorized
default:
return .notDetermined
}
} else {
return ASIdentifierManager.shared().isAdvertisingTrackingEnabled ? .authorized : .denied
}
}
func authorize(_ completion: ((AuthorizeStatus) -> Void)?) {
if #available(iOS 14.0, *) {
ATTrackingManager.requestTrackingAuthorization { status in
if completion != nil {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
completion?(self.authorizeStatus())
}
}
}
} else {
if completion != nil {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
completion?(self.authorizeStatus())
}
}
}
}
}