├── .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 | 
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 |
--------------------------------------------------------------------------------