├── .swift-version ├── permission.gif ├── WWRequestPermission ├── WWRequestPermission.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── project.pbxproj ├── WWPermissionManager │ ├── PermissionProtocol.swift │ ├── PermissionManager.swift │ ├── PermissionManagerProtocol.swift │ ├── PermissionManagerProtocol+Extension.swift │ ├── RequestPermissionLocationHandler.swift │ └── Permissions.swift └── WWRequestPermission │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Info.plist │ └── ViewController.swift ├── PermissionManager.podspec ├── .gitignore ├── AppDelegate.swift ├── README.md └── LICENSE /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /permission.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangweilucky/PermissionManager/HEAD/permission.gif -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PermissionManager.podspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pod::Spec.new do |s| 4 | s.name = 'PermissionManager' 5 | s.version = '0.5.4' 6 | s.license = 'MIT' 7 | s.summary = 'PermissionManager can action permissions' 8 | s.homepage = 'https://github.com/WangWei1993' 9 | s.authors = { 'WangWei1993' => '605479355@qq.com' } 10 | s.source = { :git => 'https://github.com/wangweilucky/PermissionManager.git', :tag => s.version } 11 | 12 | s.ios.deployment_target = '8.0' 13 | 14 | s.source_files = 'WWRequestPermission/WWPermissionManager/*.swift' 15 | end 16 | -------------------------------------------------------------------------------- /WWRequestPermission/WWPermissionManager/PermissionProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionInterface.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王伟 on 2018/4/5. 6 | // Copyright © 2018年 王伟. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// 各个权限接口 12 | @objc protocol PermissionProtocol { 13 | 14 | func request(complectionHandler: @escaping PermissionClosure) 15 | 16 | func isNotDetermined() -> Bool 17 | 18 | func isAuthorized() -> Bool 19 | 20 | func isRestrictOrDenied() -> Bool 21 | 22 | @objc optional func isNotDetermined(_ closure: @escaping PermissionClosure) 23 | 24 | @objc optional func isAuthorized(_ closure: @escaping PermissionClosure) 25 | 26 | @objc optional func isRestrictOrDenied(_ closure: @escaping PermissionClosure) 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /WWRequestPermission/WWPermissionManager/PermissionManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestPermission.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王伟 on 2017/12/20. 6 | // Copyright © 2017年 王伟. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// 权限类型 12 | public enum RequestPermissionType { 13 | case camera 14 | case photoLibrary 15 | case notification 16 | case microphone 17 | case locationAlways 18 | case locationWhenInUse 19 | case locationWithBackground 20 | case contacts 21 | case reminders 22 | case calendar 23 | } 24 | 25 | public struct PermissionsManager{} 26 | 27 | extension PermissionsManager: PermissionManagerProtocol {} 28 | 29 | extension PermissionsManager { 30 | 31 | // jumpSetting 32 | public static func jumpSetting() { 33 | 34 | if #available(iOS 10.0, *) { 35 | UIApplication.shared.open(URL.init(string: UIApplicationOpenSettingsURLString)!, 36 | options: [:], 37 | completionHandler: nil) 38 | } else { 39 | UIApplication.shared.openURL(URL.init(string: UIApplicationOpenSettingsURLString)!) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /WWRequestPermission/WWPermissionManager/PermissionManagerProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionManagerInterface.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王伟 on 2018/4/5. 6 | // Copyright © 2018年 王伟. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol PermissionManagerProtocol : PermissionRequestProtocol, PermissionStatusProtocol {} 12 | 13 | 14 | public typealias PermissionClosure = (Bool)->() 15 | 16 | 17 | // 请求接口 18 | public protocol PermissionRequestProtocol { 19 | 20 | /** 21 | 用户请求权限 22 | param: permission 权限类型 23 | */ 24 | static func request(_ permission: RequestPermissionType, _ complectionHandler: @escaping PermissionClosure) 25 | } 26 | 27 | 28 | // 状态接口 29 | public protocol PermissionStatusProtocol { 30 | 31 | /** 32 | 用户还未决定 33 | param: permission 权限类型 34 | */ 35 | static func isNotDetermined(_ permission: RequestPermissionType) -> Bool 36 | 37 | /** 38 | 用户没有权限或者拒绝 39 | param: permission 权限类型 40 | */ 41 | static func isRestrictOrDenied(_ permission: RequestPermissionType) -> Bool 42 | 43 | /** 44 | 用户允许 45 | param: permission 权限类型 46 | */ 47 | static func isAuthorized(_ permission: RequestPermissionType) -> Bool 48 | } 49 | 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /WWRequestPermission/WWPermissionManager/PermissionManagerProtocol+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionProtocol+Extension.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王大吉 on 15/8/18. 6 | // Copyright © 2018年 王伟. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // 实现请求接口 12 | public extension PermissionRequestProtocol { 13 | 14 | static func request(_ permission: RequestPermissionType, _ complectionHandler: @escaping PermissionClosure) { 15 | return getManagerForPermission(permission).request { bool in 16 | complectionHandler(bool) 17 | } 18 | } 19 | 20 | } 21 | 22 | // 实现状态获取接口 23 | public extension PermissionStatusProtocol { 24 | 25 | static func isNotDetermined(_ permission: RequestPermissionType) -> Bool { 26 | return getManagerForPermission(permission).isNotDetermined() 27 | } 28 | 29 | static func isRestrictOrDenied(_ permission: RequestPermissionType) -> Bool { 30 | return getManagerForPermission(permission).isRestrictOrDenied() 31 | } 32 | 33 | static func isAuthorized(_ permission: RequestPermissionType) -> Bool { 34 | return getManagerForPermission(permission).isAuthorized() 35 | } 36 | } 37 | 38 | // 工厂方法 39 | fileprivate func getManagerForPermission(_ permission: RequestPermissionType) -> PermissionProtocol { 40 | 41 | // 分别获取各个权限 42 | switch permission { 43 | case .camera: 44 | return WWCameraPermission() 45 | case .photoLibrary: 46 | return WWPhotoLibraryPermission() 47 | case .notification: 48 | return WWNotificationPermission() 49 | case .microphone: 50 | return WWMicrophonePermission() 51 | case .locationWhenInUse: 52 | return WWLocationPermission(type: .WhenInUse) 53 | case .locationAlways: 54 | return WWLocationPermission(type: .Always) 55 | case .locationWithBackground: 56 | return WWLocationPermission(type: .AlwaysWithBackground) 57 | case .calendar: 58 | return WWCalendarPermission() 59 | case .contacts: 60 | return WWContactsPermission() 61 | case .reminders: 62 | return WWRemindersPermission() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王伟 on 2017/12/20. 6 | // Copyright © 2017年 王伟. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王伟 on 2017/12/20. 6 | // Copyright © 2017年 王伟. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | 相机权限😯 25 | NSLocationAlwaysUsageDescription 26 | 持续时定位1😯 27 | NSLocationWhenInUseUsageDescription 28 | 使用时定位😯 29 | NSMicrophoneUsageDescription 30 | 麦克风权限😯 31 | NSPhotoLibraryUsageDescription 32 | 相册权限😯 33 | NSLocationAlwaysAndWhenInUseUsageDescription 34 | 持续时定位😯 35 | NSContactsUsageDescription 36 | 联系人😯 37 | NSRemindersUsageDescription 38 | 日程提醒😯 39 | NSCalendarsUsageDescription 40 | 日历😯 41 | UIBackgroundModes 42 | 43 | location 44 | 45 | UILaunchStoryboardName 46 | LaunchScreen 47 | UIMainStoryboardFile 48 | Main 49 | UIRequiredDeviceCapabilities 50 | 51 | armv7 52 | 53 | UISupportedInterfaceOrientations 54 | 55 | UIInterfaceOrientationPortrait 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | 59 | UISupportedInterfaceOrientations~ipad 60 | 61 | UIInterfaceOrientationPortrait 62 | UIInterfaceOrientationPortraitUpsideDown 63 | UIInterfaceOrientationLandscapeLeft 64 | UIInterfaceOrientationLandscapeRight 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PermissionManager 2 | 3 | ## 0. demo效果图 4 | 5 | ![demo](https://github.com/WangWei1993/PermissionManager/blob/master/permission.gif) 6 | 7 | ## 1. CocoaPods 8 | 9 | ```c 10 | pod 'PermissionManager' 11 | ``` 12 | 13 | 14 | ## 2. 支持的权限类型 15 | ```swift 16 | /// Permission Types 17 | public enum WWRequestPermissionType { 18 | case camera 19 | case photoLibrary 20 | case notification 21 | case microphone 22 | case locationAlways 23 | case locationWhenInUse 24 | case locationWithBackground 25 | case contacts 26 | case reminders 27 | case calendar 28 | } 29 | ``` 30 | 31 | 32 | ## 3. 使用方法 33 | 34 | ** 权限管理者接口 ** 35 | ```swift 36 | public protocol PermissionManagerProtocol { 37 | 38 | /// 判断权限是否处于未决定状态 39 | static func isNotDetermined(_ permission: RequestPermissionType) -> Bool 40 | 41 | /// 判断权限是否处于拒绝状态 42 | static func isRestrictOrDenied(_ permission: RequestPermissionType) -> Bool 43 | 44 | /// 判断权限是否处于允许状态 45 | static func isAuthorized(_ permission: RequestPermissionType) -> Bool 46 | 47 | /// 请求一个权限 48 | static func request(_ permission: RequestPermissionType, _ complectionHandler: @escaping PermissionClosure) 49 | } 50 | ``` 51 | 52 | 53 | **相机权限** 54 | ```swift 55 | 56 | PermissionsManager.request(.camera) { bool in 57 | // bool, 异步回调 58 | // true: 用户允许, false: 用户拒绝 59 | } 60 | 61 | // 相机权限是不是处于允许状态 62 | let isAuthorized = PermissionsManager.isAuthorized(.camera) 63 | 64 | // 相册权限-没有权限或者拒绝 65 | let isRestrictOrDenied = PermissionsManager.isRestrictOrDenied(.camera) 66 | 67 | // 相机权限是不是处于未决定状态 68 | let isNotDetermined = PermissionsManager.isNotDetermined(.camera) 69 | 70 | ``` 71 | 72 | **推送权限** 73 | ```swift 74 | 75 | PermissionsManager.request(.notification) { bool in 76 | // bool, 异步回调 77 | // true: 用户允许, false: 用户拒绝 78 | } 79 | 80 | // 推送权限是不是处于允许状态 81 | let isAuthorized = PermissionsManager.isAuthorized(.notification) 82 | 83 | // 推送权限-没有权限或者拒绝 84 | let isRestrictOrDenied = PermissionsManager.isRestrictOrDenied(.notification) 85 | 86 | // 推送权限是不是处于未决定状态 87 | let isNotDetermined = PermissionsManager.isNotDetermined(.notification) 88 | 89 | ``` 90 | ## 4. 注意事项 91 | 92 | > **位置权限**注意事项: 93 | 在iOS11之后,Privacy - Location Always Usage Description被降级为Privacy - Location When In Use Usage Description。 94 | 新添加Privacy - Location Always and When In Use Usage Description隐私权限,在使用后台定位的时候进行操作:Targets - Capabilities - Background Modes - location Update 这一项打钩。 95 | > **推送权限**注意事项: 96 | 推送权限在iOS10之后才包含notDetermined、authorized、authorized这三种状态,所以iOS10之前默认都会返回false。 97 | 98 | ** 如果有问题或者有更好的设计方案,请不要羞涩的issues我,会尽快回复 ** 99 | ** 邮件:15000686094@163.com ** 100 | ** 如果对你有帮助,请不要羞涩的给star吧 ** 101 | 102 | -------------------------------------------------------------------------------- /WWRequestPermission/WWPermissionManager/RequestPermissionLocationHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WWRequestPermissionLocationHandler.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王伟 on 2017/12/27. 6 | // Copyright © 2017年 王伟. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MapKit 11 | 12 | /* 13 | kCLAuthorizationStatusNotDetermined //用户尚未对该应用程序作出选择 14 | kCLAuthorizationStatusRestricted //应用程序的定位权限被限制 15 | kCLAuthorizationStatusAuthorizedAlways //允许一直获取定位 16 | kCLAuthorizationStatusAuthorizedWhenInUse //在使用时允许获取定位 17 | kCLAuthorizationStatusAuthorized //已废弃,相当于一直允许获取定位 18 | kCLAuthorizationStatusDenied //拒绝获取定位 19 | */ 20 | 21 | typealias PermissionLocationClosure = (Bool) ->Void 22 | 23 | protocol WWRequestPermissionLocationProtocol {} 24 | 25 | extension WWRequestPermissionLocationProtocol{ 26 | func isNotDetermined() -> Bool { 27 | let status = CLLocationManager.authorizationStatus() 28 | return status == .notDetermined 29 | } 30 | 31 | func isRestrictOrDenied() -> Bool { 32 | let status = CLLocationManager.authorizationStatus() 33 | return status == .restricted || status == .denied 34 | } 35 | } 36 | 37 | // 获取定位状态 38 | private var status: CLAuthorizationStatus { 39 | let status = CLLocationManager.authorizationStatus() 40 | return status 41 | } 42 | 43 | class PermissionAlwaysLocationHandler 44 | : NSObject 45 | , CLLocationManagerDelegate 46 | , WWRequestPermissionLocationProtocol { 47 | 48 | static var share = PermissionAlwaysLocationHandler() 49 | 50 | lazy var locationManager: CLLocationManager = { 51 | let locationManager = CLLocationManager() 52 | return locationManager 53 | }() 54 | 55 | var complectionHandler: PermissionLocationClosure? 56 | 57 | private var whenInUseNotRealChangeStatus: Bool = false 58 | 59 | func request(_ complectionHandler: @escaping PermissionLocationClosure) { 60 | 61 | self.complectionHandler = complectionHandler 62 | 63 | switch status { 64 | case .notDetermined, .authorizedWhenInUse: 65 | locationManager.delegate = self 66 | locationManager.requestAlwaysAuthorization() 67 | case .denied, .restricted: 68 | complectionHandler(false) 69 | case .authorizedAlways: 70 | complectionHandler(isAuthorized()) 71 | } 72 | } 73 | 74 | func isAuthorized() -> Bool { 75 | if #available(iOS 8.0, *) { 76 | if status == .authorizedAlways { 77 | return true 78 | } else { 79 | return false 80 | } 81 | } else { 82 | if status == .authorized { 83 | return true 84 | } else { 85 | return false 86 | } 87 | } 88 | } 89 | 90 | 91 | func locationManager(_ manager: CLLocationManager, 92 | didChangeAuthorization status: CLAuthorizationStatus) { 93 | 94 | if let complectionHandler = complectionHandler { 95 | complectionHandler(isAuthorized()) 96 | } 97 | } 98 | 99 | deinit { 100 | locationManager.delegate = nil 101 | } 102 | } 103 | 104 | class PermissionWhenInUseLocationHandler 105 | : NSObject 106 | , CLLocationManagerDelegate 107 | , WWRequestPermissionLocationProtocol { 108 | 109 | static var share = PermissionWhenInUseLocationHandler() 110 | 111 | lazy var locationManager: CLLocationManager = { 112 | let locationManager = CLLocationManager() 113 | locationManager.delegate = self 114 | return locationManager 115 | }() 116 | 117 | var complectionHandler: PermissionLocationClosure? 118 | 119 | private var whenInUseNotRealChangeStatus: Bool = false 120 | 121 | // notDetermined restricted denied authorizedAlways authorizedWhenInUse authorized 122 | func request(_ complectionHandler: @escaping PermissionLocationClosure) { 123 | 124 | self.complectionHandler = complectionHandler 125 | 126 | switch status { 127 | case .notDetermined , .authorizedAlways: 128 | locationManager.delegate = self 129 | locationManager.requestWhenInUseAuthorization() 130 | 131 | case .denied, .restricted: 132 | complectionHandler(false) 133 | 134 | case .authorizedWhenInUse: 135 | complectionHandler(isAuthorized()) 136 | } 137 | } 138 | 139 | func isAuthorized() -> Bool { 140 | if #available(iOS 8.0, *) { 141 | if status == .authorizedWhenInUse { 142 | return true 143 | } else { 144 | return false 145 | } 146 | } else { 147 | if status == .authorized { 148 | return true 149 | } else { 150 | return false 151 | } 152 | } 153 | } 154 | 155 | func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 156 | 157 | if status == .notDetermined { return } 158 | 159 | if let complectionHandler = complectionHandler { 160 | complectionHandler(isAuthorized()) 161 | } 162 | } 163 | 164 | deinit { 165 | locationManager.delegate = nil 166 | } 167 | } 168 | 169 | class PermissionLocationWithBackgroundHandler: PermissionAlwaysLocationHandler { 170 | 171 | override func request(_ complectionHandler: @escaping PermissionLocationClosure) 172 | { 173 | // iOS9.0以上系统除了配置info之外,还需要添加这行代码,才能实现后台定位,否则程序会crash 174 | if #available(iOS 9.0, *) { 175 | locationManager.allowsBackgroundLocationUpdates = true 176 | } 177 | super.request(complectionHandler) 178 | } 179 | 180 | } 181 | 182 | -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王伟 on 2017/12/20. 6 | // Copyright © 2017年 王伟. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private let EnableDesc = "启用" 12 | private let HasEnable = "已启用" 13 | 14 | private let Camera = "相机权限" 15 | private let PhotoLibrary = "相册权限" 16 | private let Notification = "通知权限" 17 | private let MicrophoneEnable = "语音权限" 18 | private let LocationWhenInuse = "WhenInuse权限" 19 | private let LocationAlways = "Always权限" 20 | private let LocationBackgroud = "Backgroud权限" 21 | private let Contacts = "联系人权限" 22 | private let Reminders = "日程权限" 23 | private let Calendar = "日历权限" 24 | 25 | 26 | /* 27 | 28 | NSPhotoLibraryUsageDescription 29 | App需要您的同意,才能相册 30 | 31 | NSCameraUsageDescription 32 | App需要您的同意,才能相机 33 | 34 | NSMicrophoneUsageDescription 35 | App需要您的同意,才能麦克风 36 | 37 | NSLocationUsageDescription 38 | App需要您的同意,才能位置 39 | 40 | NSLocationWhenInUseUsageDescription 41 | App需要您的同意,才能在使用期间位置 42 | 43 | NSLocationAlwaysUsageDescription 44 | App需要您的同意,才能始终位置 45 | 46 | NSCalendarsUsageDescription 47 | App需要您的同意,才能日历 48 | 49 | NSRemindersUsageDescription 50 | App需要您的同意,才能提醒事项 51 | 52 | NSMotionUsageDescription App需要您的同意,才能运动与健身 53 | 54 | NSHealthUpdateUsageDescription 55 | App需要您的同意,才能健康更新 56 | 57 | NSHealthShareUsageDescription 58 | App需要您的同意,才能健康分享 59 | 60 | NSBluetoothPeripheralUsageDescription 61 | App需要您的同意,才能蓝牙 62 | 63 | NSAppleMusicUsageDescription 64 | App需要您的同意,才能媒体资料库 65 | */ 66 | 67 | 68 | private let noEnableColor = UIColor.init(red: 85.0/255.0, 69 | green: 104.0/255.0, 70 | blue: 220.0/255.0, 71 | alpha: 1) 72 | private let enableColor = UIColor.init(red: 0, 73 | green: 0, 74 | blue: 0, 75 | alpha: 0.25) 76 | 77 | class ViewController: UIViewController { 78 | 79 | @IBOutlet weak var cameraBtn: UIButton! 80 | @IBOutlet weak var photoLibraryBtn: UIButton! 81 | @IBOutlet weak var noticeBtn: UIButton! 82 | @IBOutlet weak var microphoneBtn: UIButton! 83 | @IBOutlet weak var locationWhenInuseBtn: UIButton! 84 | @IBOutlet weak var locationAlwaysBtn: UIButton! 85 | @IBOutlet weak var locationBackgroudBtn: UIButton! 86 | @IBOutlet weak var calendarBtn: UIButton! 87 | @IBOutlet weak var contactsBtn: UIButton! 88 | @IBOutlet weak var remindersBtn: UIButton! 89 | 90 | override func viewDidLoad() { 91 | super.viewDidLoad() 92 | // Do any additional setup after loading the view, typically from a nib. 93 | 94 | cameraPermission() 95 | photoLibraryPermission() 96 | noticePermission() 97 | microphonePermission() 98 | locationWhenInusePermission() 99 | locationAlwaysPermission() 100 | locationBackgroudPermission() 101 | contactsPermission() 102 | calendarPermission() 103 | remindersPermission() 104 | } 105 | 106 | func cameraPermission() { 107 | showButtonUI(sender: cameraBtn, 108 | bool: PermissionsManager.isAuthorized(.camera)) 109 | } 110 | 111 | func photoLibraryPermission() { 112 | showButtonUI(sender: photoLibraryBtn, 113 | bool: PermissionsManager.isAuthorized(.photoLibrary)) 114 | } 115 | 116 | func noticePermission() { 117 | showButtonUI(sender: noticeBtn, 118 | bool: PermissionsManager.isAuthorized(.notification)) 119 | } 120 | 121 | func microphonePermission() { 122 | 123 | showButtonUI(sender: microphoneBtn, 124 | bool: PermissionsManager.isAuthorized(.microphone)) 125 | } 126 | 127 | func locationWhenInusePermission() { 128 | showButtonUI(sender: locationWhenInuseBtn, 129 | bool: PermissionsManager.isAuthorized(.locationWhenInUse)) 130 | } 131 | 132 | func locationAlwaysPermission() { 133 | showButtonUI(sender: locationAlwaysBtn, 134 | bool: PermissionsManager.isAuthorized(.locationAlways)) 135 | } 136 | 137 | func locationBackgroudPermission() { 138 | showButtonUI(sender: locationBackgroudBtn, 139 | bool: PermissionsManager.isAuthorized(.locationWithBackground)) 140 | } 141 | 142 | func calendarPermission() { 143 | showButtonUI(sender: calendarBtn, 144 | bool: PermissionsManager.isAuthorized(.calendar)) 145 | } 146 | 147 | func contactsPermission() { 148 | showButtonUI(sender: contactsBtn, 149 | bool: PermissionsManager.isAuthorized(.contacts)) 150 | } 151 | 152 | func remindersPermission() { 153 | showButtonUI(sender: remindersBtn, 154 | bool: PermissionsManager.isAuthorized(.reminders)) 155 | } 156 | } 157 | 158 | extension ViewController { 159 | 160 | func showButtonUI(sender: UIButton, bool: Bool) { 161 | DispatchQueue.main.async { 162 | var desc = "" 163 | switch sender.tag { 164 | case 1: 165 | desc = Camera 166 | case 2: 167 | desc = PhotoLibrary 168 | case 3: 169 | desc = Notification 170 | case 4: 171 | desc = MicrophoneEnable 172 | case 5: 173 | desc = LocationWhenInuse 174 | case 6: 175 | desc = LocationAlways 176 | case 7: 177 | desc = LocationBackgroud 178 | case 8: 179 | desc = Contacts 180 | case 9: 181 | desc = Reminders 182 | case 10: 183 | desc = Calendar 184 | default: 185 | desc = "" 186 | } 187 | 188 | desc = bool ? (desc + HasEnable) : (EnableDesc + desc) 189 | sender.setTitleColor(bool ? enableColor : noEnableColor, for: .normal) 190 | sender.setTitle(desc, for: .normal) 191 | } 192 | } 193 | 194 | /// 相机权限 195 | @IBAction func cameraPermissionRequest(_ sender: UIButton) { 196 | 197 | 198 | 199 | if PermissionsManager.isRestrictOrDenied(.camera) { 200 | PermissionsManager.jumpSetting() 201 | return 202 | } 203 | PermissionsManager.request(.camera) { bool in 204 | self.showButtonUI(sender: sender, bool: bool) 205 | } 206 | } 207 | 208 | // 相册权限 209 | @IBAction func photoLibraryPremissionRequest(_ sender: UIButton) { 210 | 211 | if PermissionsManager.isRestrictOrDenied(.photoLibrary) { 212 | PermissionsManager.jumpSetting() 213 | return 214 | } 215 | PermissionsManager.request(.photoLibrary) { bool in 216 | self.showButtonUI(sender: sender, bool: bool) 217 | } 218 | } 219 | 220 | // 麦克风权限 221 | @IBAction func microphonePermissionRequest(_ sender: UIButton) { 222 | 223 | if PermissionsManager.isRestrictOrDenied(.microphone) { 224 | PermissionsManager.jumpSetting() 225 | return 226 | } 227 | PermissionsManager.request(.microphone) { bool in 228 | self.showButtonUI(sender: sender, bool: bool) 229 | } 230 | } 231 | 232 | // 日历 233 | @IBAction func CalendarPermissionRequest(_ sender: UIButton) { 234 | 235 | if PermissionsManager.isRestrictOrDenied(.calendar) { 236 | PermissionsManager.jumpSetting() 237 | return 238 | } 239 | PermissionsManager.request(.calendar) { bool in 240 | self.showButtonUI(sender: sender, bool: bool) 241 | } 242 | } 243 | 244 | // 联系人 245 | @IBAction func ContactsPermissionRequest(_ sender: UIButton) { 246 | 247 | if PermissionsManager.isRestrictOrDenied(.contacts) { 248 | PermissionsManager.jumpSetting() 249 | return 250 | } 251 | PermissionsManager.request(.contacts) { bool in 252 | self.showButtonUI(sender: sender, bool: bool) 253 | } 254 | } 255 | 256 | // 日程提醒 257 | @IBAction func RemindersPermissionRequest(_ sender: UIButton) { 258 | 259 | if PermissionsManager.isRestrictOrDenied(.reminders) { 260 | PermissionsManager.jumpSetting() 261 | return 262 | } 263 | PermissionsManager.request(.reminders) {bool in 264 | self.showButtonUI(sender: sender, bool: bool) 265 | } 266 | } 267 | 268 | 269 | // 通知权限 270 | @IBAction func noticePremissionRequest(_ sender: UIButton) { 271 | 272 | if PermissionsManager.isRestrictOrDenied(.notification) { 273 | PermissionsManager.jumpSetting() 274 | return 275 | } 276 | PermissionsManager.request(.notification) { bool in 277 | self.showButtonUI(sender: sender, bool: bool) 278 | } 279 | } 280 | 281 | // 使用时定位 282 | @IBAction func locationWhenUsePermissionRequest(_ sender: UIButton) { 283 | 284 | if PermissionsManager.isRestrictOrDenied(.locationWhenInUse) { 285 | PermissionsManager.jumpSetting() 286 | return 287 | } 288 | PermissionsManager.request(.locationWhenInUse) { bool in 289 | self.showButtonUI(sender: sender, bool: bool) 290 | } 291 | } 292 | 293 | // 前后台定位(IOS11 以后就降级了) 294 | @IBAction func locationAlwaysPermissionRequest(_ sender: UIButton) { 295 | 296 | if PermissionsManager.isRestrictOrDenied(.locationAlways) { 297 | PermissionsManager.jumpSetting() 298 | return 299 | } 300 | PermissionsManager.request(.locationAlways) { bool in 301 | self.showButtonUI(sender: sender, bool: bool) 302 | } 303 | } 304 | 305 | // 前后台定位(IOS11开始生效,需要在info.plist设置下: 306 | // 1. Privacy - Location Always and When In Use Usage Description 307 | // 2. targets - Capabilities - Background Modes - location Update 打钩 308 | @IBAction func locationBackgroundPermissionRequest(_ sender: UIButton) { 309 | 310 | if PermissionsManager.isRestrictOrDenied(.locationWithBackground) { 311 | PermissionsManager.jumpSetting() 312 | return 313 | } 314 | PermissionsManager.request(.locationWithBackground) { bool in 315 | self.showButtonUI(sender: sender, bool: bool) 316 | } 317 | } 318 | 319 | // jumpSetting 320 | @IBAction func jumpSetting() { 321 | PermissionsManager.jumpSetting() 322 | } 323 | } 324 | 325 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /WWRequestPermission/WWPermissionManager/Permissions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WWPermissions.swift 3 | // WWRequestPermission 4 | // 5 | // Created by 王伟 on 2017/12/21. 6 | // Copyright © 2017年 王伟. All rights reserved. 7 | // 8 | 9 | 10 | import Photos 11 | import UserNotifications 12 | import MapKit 13 | import EventKit 14 | import Contacts 15 | import AVFoundation 16 | 17 | 18 | /// The app's Info.plist must contain an NSCameraUsageDescription key 19 | class WWCameraPermission: PermissionProtocol { 20 | 21 | var status: AVAuthorizationStatus { 22 | return AVCaptureDevice.authorizationStatus(for: .video) 23 | } 24 | 25 | // .authorized, .denied, .restricted, .notDetermined 26 | func request(complectionHandler: @escaping PermissionClosure) { 27 | AVCaptureDevice.requestAccess(for: .video) { (finished) in 28 | switch self.status { 29 | case .authorized: 30 | complectionHandler(true) 31 | case .denied, .restricted, .notDetermined: 32 | complectionHandler(false) 33 | } 34 | } 35 | } 36 | 37 | func isNotDetermined() -> Bool { 38 | return status == .notDetermined 39 | } 40 | 41 | func isAuthorized() -> Bool { 42 | return status == .authorized 43 | } 44 | 45 | func isRestrictOrDenied() -> Bool { 46 | return status == .restricted || AVCaptureDevice.authorizationStatus(for: .video) == .denied 47 | } 48 | } 49 | 50 | /// The app's Info.plist must contain an NSPhotoLibraryUsageDescription key 51 | class WWPhotoLibraryPermission: PermissionProtocol { 52 | 53 | var status: PHAuthorizationStatus { 54 | return PHPhotoLibrary.authorizationStatus() 55 | } 56 | 57 | // .authorized, .denied, .restricted, .notDetermined 58 | func request(complectionHandler: @escaping PermissionClosure) { 59 | PHPhotoLibrary.requestAuthorization({ finished in 60 | switch self.status { 61 | case .authorized: 62 | complectionHandler(true) 63 | case .denied, .restricted, .notDetermined: 64 | complectionHandler(false) 65 | } 66 | }) 67 | } 68 | 69 | 70 | func isNotDetermined() -> Bool { 71 | return status == PHAuthorizationStatus.notDetermined 72 | } 73 | 74 | func isAuthorized() -> Bool { 75 | return status == PHAuthorizationStatus.authorized 76 | } 77 | 78 | func isRestrictOrDenied() -> Bool { 79 | return status == PHAuthorizationStatus.restricted || PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.denied 80 | } 81 | } 82 | 83 | class WWNotificationPermission: PermissionProtocol { 84 | 85 | // notDetermined denied authorized 86 | func request(complectionHandler: @escaping PermissionClosure) { 87 | if #available(iOS 10.0, *) { 88 | let center = UNUserNotificationCenter.current() 89 | center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in 90 | if (granted) { 91 | complectionHandler(true) 92 | } else { 93 | complectionHandler(false) 94 | } 95 | } 96 | } else if #available(iOS 8, *) { 97 | UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil)) 98 | UIApplication.shared.registerForRemoteNotifications() 99 | complectionHandler(true) 100 | } else { 101 | UIApplication.shared.registerForRemoteNotifications(matching: [.alert, .badge, .sound]) 102 | UIApplication.shared.registerForRemoteNotifications() 103 | complectionHandler(true) 104 | } 105 | } 106 | 107 | @available(iOS 10.0, *) 108 | var status: UNAuthorizationStatus { 109 | var status : UNAuthorizationStatus = .denied 110 | let group = DispatchGroup() 111 | group.enter() // 阻塞线程,直到派发的任务完成 112 | UNUserNotificationCenter.current().getNotificationSettings { (setting) in 113 | status = setting.authorizationStatus 114 | group.leave() 115 | } 116 | group.wait() 117 | return status 118 | } 119 | 120 | func isNotDetermined() -> Bool { 121 | if #available(iOS 10, *) { 122 | return status == .notDetermined 123 | } else { 124 | return false 125 | } 126 | } 127 | 128 | func isAuthorized() -> Bool { 129 | if #available(iOS 10, *) { 130 | return status == .authorized 131 | } else { 132 | return false 133 | } 134 | } 135 | 136 | func isRestrictOrDenied() -> Bool { 137 | if #available(iOS 10, *) { 138 | return status == .denied 139 | } else { 140 | return false 141 | } 142 | } 143 | } 144 | 145 | 146 | class WWMicrophonePermission: PermissionProtocol { 147 | 148 | var status: AVAudioSessionRecordPermission { 149 | return AVAudioSession.sharedInstance().recordPermission() 150 | } 151 | 152 | // denied undetermined granted 153 | func request(complectionHandler: @escaping PermissionClosure) { 154 | AVAudioSession.sharedInstance().requestRecordPermission { granted in 155 | complectionHandler(granted) 156 | } 157 | } 158 | 159 | func isNotDetermined() -> Bool { 160 | return status == .undetermined 161 | } 162 | 163 | func isAuthorized() -> Bool { 164 | return status == .granted 165 | } 166 | 167 | func isRestrictOrDenied() -> Bool { 168 | return status == .denied 169 | } 170 | } 171 | 172 | // The app's Info.plist must contain an NSContactsUsageDescription key 173 | class WWContactsPermission: PermissionProtocol { 174 | 175 | // notDetermined restricted denied authorized 176 | func request(complectionHandler: @escaping PermissionClosure) { 177 | if #available(iOS 9.0, *) { 178 | let store = CNContactStore() 179 | store.requestAccess(for: .contacts, completionHandler: { (granted, error) in 180 | complectionHandler(granted) 181 | }) 182 | } else { 183 | let addressBookRef: ABAddressBook = ABAddressBookCreateWithOptions(nil, nil).takeRetainedValue() 184 | ABAddressBookRequestAccessWithCompletion(addressBookRef) { 185 | (granted: Bool, error: CFError?) in 186 | complectionHandler(granted) 187 | } 188 | } 189 | } 190 | 191 | func isNotDetermined() -> Bool { 192 | if #available(iOS 9.0, *) { 193 | return CNContactStore.authorizationStatus(for: .contacts) == .notDetermined 194 | } else { 195 | return ABAddressBookGetAuthorizationStatus() == .notDetermined 196 | } 197 | } 198 | 199 | func isAuthorized() -> Bool { 200 | if #available(iOS 9.0, *) { 201 | return CNContactStore.authorizationStatus(for: .contacts) == .authorized 202 | } else { 203 | return ABAddressBookGetAuthorizationStatus() == .authorized 204 | } 205 | } 206 | 207 | func isRestrictOrDenied() -> Bool { 208 | if #available(iOS 9.0, *) { 209 | let status = CNContactStore.authorizationStatus(for: .contacts) 210 | return status == .restricted || status == .denied 211 | } else { 212 | let status = ABAddressBookGetAuthorizationStatus() 213 | return status == .restricted || status == .denied 214 | } 215 | } 216 | } 217 | 218 | // The app's Info.plist must contain an NSRemindersUsageDescription key 219 | class WWRemindersPermission: PermissionProtocol { 220 | 221 | var status: EKAuthorizationStatus { 222 | let status = EKEventStore.authorizationStatus(for: EKEntityType.reminder) 223 | return status 224 | } 225 | 226 | func request(complectionHandler: @escaping PermissionClosure) { 227 | let eventStore = EKEventStore() 228 | eventStore.requestAccess(to: EKEntityType.reminder, completion: { 229 | (accessGranted: Bool, error: Error?) in 230 | complectionHandler(accessGranted) 231 | }) 232 | } 233 | 234 | 235 | func isNotDetermined() -> Bool { 236 | return status == EKAuthorizationStatus.notDetermined 237 | } 238 | 239 | func isAuthorized() -> Bool { 240 | return status == EKAuthorizationStatus.authorized 241 | } 242 | 243 | func isRestrictOrDenied() -> Bool { 244 | return status == EKAuthorizationStatus.restricted || status == EKAuthorizationStatus.denied 245 | } 246 | } 247 | 248 | // The app's Info.plist must contain an NSCalendarsUsageDescription key 249 | class WWCalendarPermission: PermissionProtocol { 250 | 251 | var status: EKAuthorizationStatus { 252 | return EKEventStore.authorizationStatus(for: EKEntityType.event) 253 | } 254 | 255 | func request(complectionHandler: @escaping PermissionClosure) { 256 | let eventStore = EKEventStore() 257 | eventStore.requestAccess(to: EKEntityType.event, completion: { 258 | (accessGranted: Bool, error: Error?) in 259 | complectionHandler(accessGranted) 260 | }) 261 | } 262 | 263 | func isNotDetermined() -> Bool { 264 | return status == EKAuthorizationStatus.notDetermined 265 | } 266 | 267 | func isAuthorized() -> Bool { 268 | return status == EKAuthorizationStatus.authorized 269 | } 270 | 271 | func isRestrictOrDenied() -> Bool { 272 | return status == EKAuthorizationStatus.restricted || status == EKAuthorizationStatus.denied 273 | } 274 | } 275 | 276 | 277 | 278 | class WWLocationPermission: PermissionProtocol { 279 | 280 | enum WWLocationType { 281 | case Always 282 | case WhenInUse 283 | case AlwaysWithBackground 284 | } 285 | 286 | var type: WWLocationType 287 | 288 | init(type: WWLocationType) { 289 | 290 | self.type = type 291 | } 292 | 293 | func request(complectionHandler: @escaping PermissionClosure) { 294 | switch type { 295 | case .Always: 296 | PermissionAlwaysLocationHandler.share.request({ (authorized) in 297 | complectionHandler(authorized) 298 | }) 299 | 300 | case .WhenInUse: 301 | PermissionWhenInUseLocationHandler.share.request({ (authorized) in 302 | complectionHandler(authorized) 303 | }) 304 | 305 | case .AlwaysWithBackground: 306 | PermissionLocationWithBackgroundHandler.share.request({ (authorized) in 307 | complectionHandler(authorized) 308 | }) 309 | } 310 | } 311 | 312 | 313 | func isNotDetermined() -> Bool { 314 | switch type { 315 | case .Always: 316 | return PermissionAlwaysLocationHandler.share.isNotDetermined() 317 | case .WhenInUse: 318 | return PermissionWhenInUseLocationHandler.share.isNotDetermined() 319 | case .AlwaysWithBackground: 320 | return PermissionLocationWithBackgroundHandler.share.isNotDetermined() 321 | } 322 | } 323 | 324 | func isAuthorized() -> Bool { 325 | switch type { 326 | case .Always: 327 | return PermissionAlwaysLocationHandler.share.isAuthorized() 328 | case .WhenInUse: 329 | return PermissionWhenInUseLocationHandler.share.isAuthorized() 330 | case .AlwaysWithBackground: 331 | return PermissionLocationWithBackgroundHandler.share.isAuthorized() 332 | } 333 | } 334 | 335 | func isRestrictOrDenied() -> Bool { 336 | switch type { 337 | case .Always: 338 | return PermissionAlwaysLocationHandler.share.isRestrictOrDenied() 339 | case .WhenInUse: 340 | return PermissionWhenInUseLocationHandler.share.isRestrictOrDenied() 341 | case .AlwaysWithBackground: 342 | return PermissionLocationWithBackgroundHandler.share.isRestrictOrDenied() 343 | } 344 | } 345 | 346 | deinit { 347 | 348 | } 349 | } 350 | 351 | 352 | 353 | -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 33 | 42 | 51 | 60 | 69 | 78 | 87 | 96 | 105 | 114 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /WWRequestPermission/WWRequestPermission.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0049D37721240160003DD0CE /* PermissionManagerProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0049D37621240160003DD0CE /* PermissionManagerProtocol+Extension.swift */; }; 11 | 4A38EFF51FEA7BA000F8D480 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A38EFF41FEA7BA000F8D480 /* AppDelegate.swift */; }; 12 | 4A38EFF71FEA7BA000F8D480 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A38EFF61FEA7BA000F8D480 /* ViewController.swift */; }; 13 | 4A38EFFA1FEA7BA000F8D480 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4A38EFF81FEA7BA000F8D480 /* Main.storyboard */; }; 14 | 4A38EFFC1FEA7BA000F8D480 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4A38EFFB1FEA7BA000F8D480 /* Assets.xcassets */; }; 15 | 4A38EFFF1FEA7BA000F8D480 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4A38EFFD1FEA7BA000F8D480 /* LaunchScreen.storyboard */; }; 16 | 4A97A8FF2075B4AA00BFF02C /* PermissionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A97A8FE2075B4AA00BFF02C /* PermissionProtocol.swift */; }; 17 | 4A97A9012075B4E700BFF02C /* PermissionManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A97A9002075B4E700BFF02C /* PermissionManagerProtocol.swift */; }; 18 | 4AE2CCBC1FF3BD4E004108A6 /* Permissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE2CCB91FF3BD4E004108A6 /* Permissions.swift */; }; 19 | 4AE2CCBD1FF3BD4E004108A6 /* RequestPermissionLocationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE2CCBA1FF3BD4E004108A6 /* RequestPermissionLocationHandler.swift */; }; 20 | 4AE2CCBE1FF3BD4E004108A6 /* PermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE2CCBB1FF3BD4E004108A6 /* PermissionManager.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 0049D37621240160003DD0CE /* PermissionManagerProtocol+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PermissionManagerProtocol+Extension.swift"; sourceTree = ""; }; 25 | 4A38EFF11FEA7BA000F8D480 /* WWRequestPermission.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WWRequestPermission.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 4A38EFF41FEA7BA000F8D480 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 27 | 4A38EFF61FEA7BA000F8D480 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 28 | 4A38EFF91FEA7BA000F8D480 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 4A38EFFB1FEA7BA000F8D480 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | 4A38EFFE1FEA7BA000F8D480 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | 4A38F0001FEA7BA000F8D480 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 4A97A8FE2075B4AA00BFF02C /* PermissionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionProtocol.swift; sourceTree = ""; }; 33 | 4A97A9002075B4E700BFF02C /* PermissionManagerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionManagerProtocol.swift; sourceTree = ""; }; 34 | 4AE2CCB91FF3BD4E004108A6 /* Permissions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Permissions.swift; sourceTree = ""; }; 35 | 4AE2CCBA1FF3BD4E004108A6 /* RequestPermissionLocationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestPermissionLocationHandler.swift; sourceTree = ""; }; 36 | 4AE2CCBB1FF3BD4E004108A6 /* PermissionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionManager.swift; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | 4A38EFEE1FEA7BA000F8D480 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | /* End PBXFrameworksBuildPhase section */ 48 | 49 | /* Begin PBXGroup section */ 50 | 4A1B79751FF11B0D00BF30C6 /* Frameworks */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | ); 54 | name = Frameworks; 55 | sourceTree = ""; 56 | }; 57 | 4A38EFE81FEA7BA000F8D480 = { 58 | isa = PBXGroup; 59 | children = ( 60 | 4A38EFF31FEA7BA000F8D480 /* WWRequestPermission */, 61 | 4A38EFF21FEA7BA000F8D480 /* Products */, 62 | 4A1B79751FF11B0D00BF30C6 /* Frameworks */, 63 | ); 64 | sourceTree = ""; 65 | }; 66 | 4A38EFF21FEA7BA000F8D480 /* Products */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 4A38EFF11FEA7BA000F8D480 /* WWRequestPermission.app */, 70 | ); 71 | name = Products; 72 | sourceTree = ""; 73 | }; 74 | 4A38EFF31FEA7BA000F8D480 /* WWRequestPermission */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 4AE2CCB81FF3BD4E004108A6 /* WWPermissionManager */, 78 | 4A38EFF41FEA7BA000F8D480 /* AppDelegate.swift */, 79 | 4A38EFF61FEA7BA000F8D480 /* ViewController.swift */, 80 | 4A38EFF81FEA7BA000F8D480 /* Main.storyboard */, 81 | 4A38EFFB1FEA7BA000F8D480 /* Assets.xcassets */, 82 | 4A38EFFD1FEA7BA000F8D480 /* LaunchScreen.storyboard */, 83 | 4A38F0001FEA7BA000F8D480 /* Info.plist */, 84 | ); 85 | path = WWRequestPermission; 86 | sourceTree = ""; 87 | }; 88 | 4AE2CCB81FF3BD4E004108A6 /* WWPermissionManager */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 4A97A8FE2075B4AA00BFF02C /* PermissionProtocol.swift */, 92 | 4AE2CCB91FF3BD4E004108A6 /* Permissions.swift */, 93 | 4AE2CCBA1FF3BD4E004108A6 /* RequestPermissionLocationHandler.swift */, 94 | 4AE2CCBB1FF3BD4E004108A6 /* PermissionManager.swift */, 95 | 4A97A9002075B4E700BFF02C /* PermissionManagerProtocol.swift */, 96 | 0049D37621240160003DD0CE /* PermissionManagerProtocol+Extension.swift */, 97 | ); 98 | path = WWPermissionManager; 99 | sourceTree = SOURCE_ROOT; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 4A38EFF01FEA7BA000F8D480 /* WWRequestPermission */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 4A38F0031FEA7BA000F8D480 /* Build configuration list for PBXNativeTarget "WWRequestPermission" */; 107 | buildPhases = ( 108 | 4A38EFED1FEA7BA000F8D480 /* Sources */, 109 | 4A38EFEE1FEA7BA000F8D480 /* Frameworks */, 110 | 4A38EFEF1FEA7BA000F8D480 /* Resources */, 111 | ); 112 | buildRules = ( 113 | ); 114 | dependencies = ( 115 | ); 116 | name = WWRequestPermission; 117 | productName = WWRequestPermission; 118 | productReference = 4A38EFF11FEA7BA000F8D480 /* WWRequestPermission.app */; 119 | productType = "com.apple.product-type.application"; 120 | }; 121 | /* End PBXNativeTarget section */ 122 | 123 | /* Begin PBXProject section */ 124 | 4A38EFE91FEA7BA000F8D480 /* Project object */ = { 125 | isa = PBXProject; 126 | attributes = { 127 | LastSwiftUpdateCheck = 0920; 128 | LastUpgradeCheck = 0940; 129 | ORGANIZATIONNAME = "王伟"; 130 | TargetAttributes = { 131 | 4A38EFF01FEA7BA000F8D480 = { 132 | CreatedOnToolsVersion = 9.2; 133 | ProvisioningStyle = Automatic; 134 | SystemCapabilities = { 135 | com.apple.BackgroundModes = { 136 | enabled = 1; 137 | }; 138 | com.apple.Maps.iOS = { 139 | enabled = 0; 140 | }; 141 | }; 142 | }; 143 | }; 144 | }; 145 | buildConfigurationList = 4A38EFEC1FEA7BA000F8D480 /* Build configuration list for PBXProject "WWRequestPermission" */; 146 | compatibilityVersion = "Xcode 8.0"; 147 | developmentRegion = en; 148 | hasScannedForEncodings = 0; 149 | knownRegions = ( 150 | en, 151 | Base, 152 | ); 153 | mainGroup = 4A38EFE81FEA7BA000F8D480; 154 | productRefGroup = 4A38EFF21FEA7BA000F8D480 /* Products */; 155 | projectDirPath = ""; 156 | projectRoot = ""; 157 | targets = ( 158 | 4A38EFF01FEA7BA000F8D480 /* WWRequestPermission */, 159 | ); 160 | }; 161 | /* End PBXProject section */ 162 | 163 | /* Begin PBXResourcesBuildPhase section */ 164 | 4A38EFEF1FEA7BA000F8D480 /* Resources */ = { 165 | isa = PBXResourcesBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | 4A38EFFF1FEA7BA000F8D480 /* LaunchScreen.storyboard in Resources */, 169 | 4A38EFFC1FEA7BA000F8D480 /* Assets.xcassets in Resources */, 170 | 4A38EFFA1FEA7BA000F8D480 /* Main.storyboard in Resources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXResourcesBuildPhase section */ 175 | 176 | /* Begin PBXSourcesBuildPhase section */ 177 | 4A38EFED1FEA7BA000F8D480 /* Sources */ = { 178 | isa = PBXSourcesBuildPhase; 179 | buildActionMask = 2147483647; 180 | files = ( 181 | 0049D37721240160003DD0CE /* PermissionManagerProtocol+Extension.swift in Sources */, 182 | 4A38EFF71FEA7BA000F8D480 /* ViewController.swift in Sources */, 183 | 4A38EFF51FEA7BA000F8D480 /* AppDelegate.swift in Sources */, 184 | 4AE2CCBC1FF3BD4E004108A6 /* Permissions.swift in Sources */, 185 | 4AE2CCBD1FF3BD4E004108A6 /* RequestPermissionLocationHandler.swift in Sources */, 186 | 4A97A9012075B4E700BFF02C /* PermissionManagerProtocol.swift in Sources */, 187 | 4A97A8FF2075B4AA00BFF02C /* PermissionProtocol.swift in Sources */, 188 | 4AE2CCBE1FF3BD4E004108A6 /* PermissionManager.swift in Sources */, 189 | ); 190 | runOnlyForDeploymentPostprocessing = 0; 191 | }; 192 | /* End PBXSourcesBuildPhase section */ 193 | 194 | /* Begin PBXVariantGroup section */ 195 | 4A38EFF81FEA7BA000F8D480 /* Main.storyboard */ = { 196 | isa = PBXVariantGroup; 197 | children = ( 198 | 4A38EFF91FEA7BA000F8D480 /* Base */, 199 | ); 200 | name = Main.storyboard; 201 | sourceTree = ""; 202 | }; 203 | 4A38EFFD1FEA7BA000F8D480 /* LaunchScreen.storyboard */ = { 204 | isa = PBXVariantGroup; 205 | children = ( 206 | 4A38EFFE1FEA7BA000F8D480 /* Base */, 207 | ); 208 | name = LaunchScreen.storyboard; 209 | sourceTree = ""; 210 | }; 211 | /* End PBXVariantGroup section */ 212 | 213 | /* Begin XCBuildConfiguration section */ 214 | 4A38F0011FEA7BA000F8D480 /* Debug */ = { 215 | isa = XCBuildConfiguration; 216 | buildSettings = { 217 | ALWAYS_SEARCH_USER_PATHS = NO; 218 | CLANG_ANALYZER_NONNULL = YES; 219 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 220 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 221 | CLANG_CXX_LIBRARY = "libc++"; 222 | CLANG_ENABLE_MODULES = YES; 223 | CLANG_ENABLE_OBJC_ARC = YES; 224 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 225 | CLANG_WARN_BOOL_CONVERSION = YES; 226 | CLANG_WARN_COMMA = YES; 227 | CLANG_WARN_CONSTANT_CONVERSION = YES; 228 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 229 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 230 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 231 | CLANG_WARN_EMPTY_BODY = YES; 232 | CLANG_WARN_ENUM_CONVERSION = YES; 233 | CLANG_WARN_INFINITE_RECURSION = YES; 234 | CLANG_WARN_INT_CONVERSION = YES; 235 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 236 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 237 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 238 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 239 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 240 | CLANG_WARN_STRICT_PROTOTYPES = YES; 241 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 242 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 243 | CLANG_WARN_UNREACHABLE_CODE = YES; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | CODE_SIGN_IDENTITY = "iPhone Developer"; 246 | COPY_PHASE_STRIP = NO; 247 | DEBUG_INFORMATION_FORMAT = dwarf; 248 | ENABLE_STRICT_OBJC_MSGSEND = YES; 249 | ENABLE_TESTABILITY = YES; 250 | GCC_C_LANGUAGE_STANDARD = gnu11; 251 | GCC_DYNAMIC_NO_PIC = NO; 252 | GCC_NO_COMMON_BLOCKS = YES; 253 | GCC_OPTIMIZATION_LEVEL = 0; 254 | GCC_PREPROCESSOR_DEFINITIONS = ( 255 | "DEBUG=1", 256 | "$(inherited)", 257 | ); 258 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 259 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 260 | GCC_WARN_UNDECLARED_SELECTOR = YES; 261 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 262 | GCC_WARN_UNUSED_FUNCTION = YES; 263 | GCC_WARN_UNUSED_VARIABLE = YES; 264 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 265 | MTL_ENABLE_DEBUG_INFO = YES; 266 | ONLY_ACTIVE_ARCH = YES; 267 | SDKROOT = iphoneos; 268 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 269 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 270 | }; 271 | name = Debug; 272 | }; 273 | 4A38F0021FEA7BA000F8D480 /* Release */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_ANALYZER_NONNULL = YES; 278 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 279 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 280 | CLANG_CXX_LIBRARY = "libc++"; 281 | CLANG_ENABLE_MODULES = YES; 282 | CLANG_ENABLE_OBJC_ARC = YES; 283 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 284 | CLANG_WARN_BOOL_CONVERSION = YES; 285 | CLANG_WARN_COMMA = YES; 286 | CLANG_WARN_CONSTANT_CONVERSION = YES; 287 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 288 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 289 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 290 | CLANG_WARN_EMPTY_BODY = YES; 291 | CLANG_WARN_ENUM_CONVERSION = YES; 292 | CLANG_WARN_INFINITE_RECURSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 296 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 297 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 298 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 299 | CLANG_WARN_STRICT_PROTOTYPES = YES; 300 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 301 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 302 | CLANG_WARN_UNREACHABLE_CODE = YES; 303 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 304 | CODE_SIGN_IDENTITY = "iPhone Developer"; 305 | COPY_PHASE_STRIP = NO; 306 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 307 | ENABLE_NS_ASSERTIONS = NO; 308 | ENABLE_STRICT_OBJC_MSGSEND = YES; 309 | GCC_C_LANGUAGE_STANDARD = gnu11; 310 | GCC_NO_COMMON_BLOCKS = YES; 311 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 312 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 313 | GCC_WARN_UNDECLARED_SELECTOR = YES; 314 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 315 | GCC_WARN_UNUSED_FUNCTION = YES; 316 | GCC_WARN_UNUSED_VARIABLE = YES; 317 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 318 | MTL_ENABLE_DEBUG_INFO = NO; 319 | SDKROOT = iphoneos; 320 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 321 | VALIDATE_PRODUCT = YES; 322 | }; 323 | name = Release; 324 | }; 325 | 4A38F0041FEA7BA000F8D480 /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 329 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 330 | CODE_SIGN_STYLE = Automatic; 331 | DEVELOPMENT_TEAM = PE79EJX2E2; 332 | INFOPLIST_FILE = WWRequestPermission/Info.plist; 333 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 334 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 335 | PRODUCT_BUNDLE_IDENTIFIER = safetyWifi.weiwang.com.WWRequestPermission; 336 | PRODUCT_NAME = "$(TARGET_NAME)"; 337 | PROVISIONING_PROFILE_SPECIFIER = ""; 338 | SWIFT_VERSION = 4.0; 339 | TARGETED_DEVICE_FAMILY = "1,2"; 340 | }; 341 | name = Debug; 342 | }; 343 | 4A38F0051FEA7BA000F8D480 /* Release */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 347 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 348 | CODE_SIGN_STYLE = Automatic; 349 | DEVELOPMENT_TEAM = PE79EJX2E2; 350 | INFOPLIST_FILE = WWRequestPermission/Info.plist; 351 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 352 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 353 | PRODUCT_BUNDLE_IDENTIFIER = safetyWifi.weiwang.com.WWRequestPermission; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | PROVISIONING_PROFILE_SPECIFIER = ""; 356 | SWIFT_VERSION = 4.0; 357 | TARGETED_DEVICE_FAMILY = "1,2"; 358 | }; 359 | name = Release; 360 | }; 361 | /* End XCBuildConfiguration section */ 362 | 363 | /* Begin XCConfigurationList section */ 364 | 4A38EFEC1FEA7BA000F8D480 /* Build configuration list for PBXProject "WWRequestPermission" */ = { 365 | isa = XCConfigurationList; 366 | buildConfigurations = ( 367 | 4A38F0011FEA7BA000F8D480 /* Debug */, 368 | 4A38F0021FEA7BA000F8D480 /* Release */, 369 | ); 370 | defaultConfigurationIsVisible = 0; 371 | defaultConfigurationName = Release; 372 | }; 373 | 4A38F0031FEA7BA000F8D480 /* Build configuration list for PBXNativeTarget "WWRequestPermission" */ = { 374 | isa = XCConfigurationList; 375 | buildConfigurations = ( 376 | 4A38F0041FEA7BA000F8D480 /* Debug */, 377 | 4A38F0051FEA7BA000F8D480 /* Release */, 378 | ); 379 | defaultConfigurationIsVisible = 0; 380 | defaultConfigurationName = Release; 381 | }; 382 | /* End XCConfigurationList section */ 383 | }; 384 | rootObject = 4A38EFE91FEA7BA000F8D480 /* Project object */; 385 | } 386 | --------------------------------------------------------------------------------