├── .github └── CODEOWNERS ├── .gitignore ├── .infrastructure └── azp │ └── security-pipeline.yml ├── .travis.yml ├── LICENSE ├── PermissionsKit-macOS.podspec ├── PermissionsKit.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── PermissionsKit.xcscheme ├── PermissionsKit ├── Info.plist ├── PermissionsKit.h ├── Private │ ├── Calendar │ │ ├── MPCalendarAuthorizer.h │ │ └── MPCalendarAuthorizer.m │ ├── Contacts │ │ ├── MPContactsAuthorization.h │ │ ├── MPContactsAuthorization.m │ │ ├── MPContactsAuthorizer.h │ │ └── MPContactsAuthorizer.m │ ├── FullDiskAccess │ │ ├── MPFullDiskAccessAuthorizer.h │ │ └── MPFullDiskAccessAuthorizer.m │ ├── MPAuthorizer.h │ └── Photos │ │ ├── MPPhotosAuthorizer.h │ │ └── MPPhotosAuthorizer.m └── Public │ ├── MPAuthorizationStatus.h │ ├── MPPermissionType.h │ ├── MPPermissionsKit.h │ └── MPPermissionsKit.m ├── PermissionsKitTestApp copy-Info.plist ├── PermissionsKitTestApp ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ └── MainMenu.xib ├── Entitlements │ └── PermissionsKitTestApp-Sandboxed.entitlements ├── Info.plist └── main.m ├── README.md ├── Screenshots ├── calendar.png ├── contacts.png ├── full_disk_access.png ├── logo.png ├── reminders.png └── test_app.png └── Scripts └── buildAndZipAll.sh /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Security checks owner is Security team 2 | .infrastructure/azp/security-pipeline.yml @MacPaw/security -------------------------------------------------------------------------------- /.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 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots/**/*.png 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | 65 | .DS_Store 66 | -------------------------------------------------------------------------------- /.infrastructure/azp/security-pipeline.yml: -------------------------------------------------------------------------------- 1 | name: security-scan 2 | trigger: none 3 | pr: 4 | - master 5 | 6 | variables: 7 | - group: vault 8 | - group: github 9 | 10 | resources: 11 | repositories: 12 | - repository: sec-azp-pipelines 13 | type: github 14 | name: MacPaw/sec-azp-pipelines 15 | ref: refs/heads/main 16 | endpoint: MacPaw 17 | 18 | stages: 19 | - stage: main 20 | pool: 21 | name: default-sre 22 | displayName: scan 23 | jobs: 24 | - template: azp/templates/base-security-checks.yaml@sec-azp-pipelines 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | xcode_project: PermissionsKit.xcodeproj 3 | xcode_scheme: PermissionsKit 4 | script: "set -o pipefail && xcodebuild -project PermissionsKit.xcodeproj -scheme PermissionsKit build | xcpretty" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 MacPaw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PermissionsKit-macOS.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'PermissionsKit-macOS' 3 | s.version = '1.0.6' 4 | s.summary = 'The convenience wrapper on macOS permissions API, including Mojave Full Disk Access.' 5 | s.description = <<-DESC 6 | The convenient wrapper on macOS permissions API. You can check and request user permissions to access: Calendar, Reminders, Contacts, Photos and Full Disk Access on Mojave. 7 | DESC 8 | s.module_name = 'PermissionsKit' 9 | s.homepage = 'https://github.com/MacPaw/PermissionsKit' 10 | # s.screenshots = 'https://raw.githubusercontent.com/MacPaw/PermissionsKit/master/Screenshots/calendar.png', 'https://raw.githubusercontent.com/MacPaw/PermissionsKit/master/Screenshots/contacts.png', 'https://raw.githubusercontent.com/MacPaw/PermissionsKit/master/Screenshots/reminders.png', 'https://raw.githubusercontent.com/MacPaw/PermissionsKit/master/Screenshots/full_disk_access.png' 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { 'Serg Krivoblotsky' => 'krivoblotsky@macpaw.com' } 13 | s.source = { :git => 'https://github.com/MacPaw/PermissionsKit.git', :tag => s.version.to_s } 14 | s.social_media_url = 'https://twitter.com/Krivoblotsky' 15 | 16 | s.platform = :osx 17 | s.osx.deployment_target = "10.13" 18 | 19 | s.source_files = 'PermissionsKit/Public/**/*', 'PermissionsKit/Private/**/*', 'PermissionsKit/PermissionsKit.h' 20 | 21 | s.public_header_files = 'PermissionsKit/Public/**/*.h', 'PermissionsKit/PermissionsKit.h' 22 | s.frameworks = 'Cocoa', 'Contacts', 'EventKit', 'Photos' 23 | end 24 | -------------------------------------------------------------------------------- /PermissionsKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 30093F5021C1522F004FD64E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A706EB78214939660098836A /* main.m */; }; 11 | 30093F5121C1522F004FD64E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A706EB70214939650098836A /* AppDelegate.m */; }; 12 | 30093F5321C1522F004FD64E /* PermissionsKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A706EB5E214938530098836A /* PermissionsKit.framework */; }; 13 | 30093F5521C1522F004FD64E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = A706EB74214939660098836A /* MainMenu.xib */; }; 14 | 30093F5721C1522F004FD64E /* PermissionsKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A706EB5E214938530098836A /* PermissionsKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 15 | A706EB63214938530098836A /* PermissionsKit.h in Headers */ = {isa = PBXBuildFile; fileRef = A706EB61214938530098836A /* PermissionsKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 16 | A706EB71214939650098836A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A706EB70214939650098836A /* AppDelegate.m */; }; 17 | A706EB76214939660098836A /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = A706EB74214939660098836A /* MainMenu.xib */; }; 18 | A706EB79214939660098836A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A706EB78214939660098836A /* main.m */; }; 19 | A76D590721493C5C0091E347 /* MPPermissionsKit.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D590521493C5C0091E347 /* MPPermissionsKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 20 | A76D590821493C5C0091E347 /* MPPermissionsKit.m in Sources */ = {isa = PBXBuildFile; fileRef = A76D590621493C5C0091E347 /* MPPermissionsKit.m */; }; 21 | A76D590B21493D480091E347 /* MPAuthorizationStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D590A21493CDB0091E347 /* MPAuthorizationStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; 22 | A76D590C21493D4B0091E347 /* MPPermissionType.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D590921493CA70091E347 /* MPPermissionType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 23 | A76D590E21493EB00091E347 /* MPAuthorizer.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D590D21493EB00091E347 /* MPAuthorizer.h */; }; 24 | A76D591221493F440091E347 /* MPContactsAuthorizer.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D591021493F440091E347 /* MPContactsAuthorizer.h */; }; 25 | A76D591321493F440091E347 /* MPContactsAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = A76D591121493F440091E347 /* MPContactsAuthorizer.m */; }; 26 | A76D5917214941CB0091E347 /* MPCalendarAuthorizer.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D5915214941CB0091E347 /* MPCalendarAuthorizer.h */; }; 27 | A76D5918214941CB0091E347 /* MPCalendarAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = A76D5916214941CB0091E347 /* MPCalendarAuthorizer.m */; }; 28 | A76D5921214948D40091E347 /* MPFullDiskAccessAuthorizer.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D591F214948D40091E347 /* MPFullDiskAccessAuthorizer.h */; }; 29 | A76D5922214948D40091E347 /* MPFullDiskAccessAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = A76D5920214948D40091E347 /* MPFullDiskAccessAuthorizer.m */; }; 30 | A76D592A21494DCB0091E347 /* MPPhotosAuthorizer.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D592821494DCB0091E347 /* MPPhotosAuthorizer.h */; }; 31 | A76D592B21494DCB0091E347 /* MPPhotosAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = A76D592921494DCB0091E347 /* MPPhotosAuthorizer.m */; }; 32 | A76D592D21495A960091E347 /* PermissionsKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A706EB5E214938530098836A /* PermissionsKit.framework */; }; 33 | A76D592E21495A960091E347 /* PermissionsKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A706EB5E214938530098836A /* PermissionsKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 34 | A76D593721496DE40091E347 /* MPContactsAuthorization.h in Headers */ = {isa = PBXBuildFile; fileRef = A76D593521496DE40091E347 /* MPContactsAuthorization.h */; }; 35 | A76D593821496DE40091E347 /* MPContactsAuthorization.m in Sources */ = {isa = PBXBuildFile; fileRef = A76D593621496DE40091E347 /* MPContactsAuthorization.m */; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXContainerItemProxy section */ 39 | 30093F4E21C1522F004FD64E /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = A706EB55214938530098836A /* Project object */; 42 | proxyType = 1; 43 | remoteGlobalIDString = A706EB5D214938530098836A; 44 | remoteInfo = PermissionsKit; 45 | }; 46 | A706EB7E21493A1A0098836A /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = A706EB55214938530098836A /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = A706EB5D214938530098836A; 51 | remoteInfo = PermissionsKit; 52 | }; 53 | /* End PBXContainerItemProxy section */ 54 | 55 | /* Begin PBXCopyFilesBuildPhase section */ 56 | 30093F5621C1522F004FD64E /* Embed Frameworks */ = { 57 | isa = PBXCopyFilesBuildPhase; 58 | buildActionMask = 2147483647; 59 | dstPath = ""; 60 | dstSubfolderSpec = 10; 61 | files = ( 62 | 30093F5721C1522F004FD64E /* PermissionsKit.framework in Embed Frameworks */, 63 | ); 64 | name = "Embed Frameworks"; 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | A76D592F21495A960091E347 /* Embed Frameworks */ = { 68 | isa = PBXCopyFilesBuildPhase; 69 | buildActionMask = 2147483647; 70 | dstPath = ""; 71 | dstSubfolderSpec = 10; 72 | files = ( 73 | A76D592E21495A960091E347 /* PermissionsKit.framework in Embed Frameworks */, 74 | ); 75 | name = "Embed Frameworks"; 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXCopyFilesBuildPhase section */ 79 | 80 | /* Begin PBXFileReference section */ 81 | 30093F5B21C1522F004FD64E /* PermissionsKitTestApp-Sandboxed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PermissionsKitTestApp-Sandboxed.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | 30093F5C21C1522F004FD64E /* PermissionsKitTestApp copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "PermissionsKitTestApp copy-Info.plist"; path = "/Users/roman/Repositories/PermissionsKit/PermissionsKitTestApp copy-Info.plist"; sourceTree = ""; }; 83 | 30093F5D21C15244004FD64E /* PermissionsKitTestApp-Sandboxed.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "PermissionsKitTestApp-Sandboxed.entitlements"; sourceTree = ""; }; 84 | A706EB5E214938530098836A /* PermissionsKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PermissionsKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | A706EB61214938530098836A /* PermissionsKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PermissionsKit.h; sourceTree = ""; }; 86 | A706EB62214938530098836A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 87 | A706EB6D214939650098836A /* PermissionsKitTestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PermissionsKitTestApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | A706EB6F214939650098836A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 89 | A706EB70214939650098836A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 90 | A706EB75214939660098836A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 91 | A706EB77214939660098836A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 92 | A706EB78214939660098836A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 93 | A76D590521493C5C0091E347 /* MPPermissionsKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPermissionsKit.h; sourceTree = ""; }; 94 | A76D590621493C5C0091E347 /* MPPermissionsKit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPermissionsKit.m; sourceTree = ""; }; 95 | A76D590921493CA70091E347 /* MPPermissionType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPermissionType.h; sourceTree = ""; }; 96 | A76D590A21493CDB0091E347 /* MPAuthorizationStatus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAuthorizationStatus.h; sourceTree = ""; }; 97 | A76D590D21493EB00091E347 /* MPAuthorizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAuthorizer.h; sourceTree = ""; }; 98 | A76D591021493F440091E347 /* MPContactsAuthorizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPContactsAuthorizer.h; sourceTree = ""; }; 99 | A76D591121493F440091E347 /* MPContactsAuthorizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPContactsAuthorizer.m; sourceTree = ""; }; 100 | A76D5915214941CB0091E347 /* MPCalendarAuthorizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPCalendarAuthorizer.h; sourceTree = ""; }; 101 | A76D5916214941CB0091E347 /* MPCalendarAuthorizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPCalendarAuthorizer.m; sourceTree = ""; }; 102 | A76D591F214948D40091E347 /* MPFullDiskAccessAuthorizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPFullDiskAccessAuthorizer.h; sourceTree = ""; }; 103 | A76D5920214948D40091E347 /* MPFullDiskAccessAuthorizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPFullDiskAccessAuthorizer.m; sourceTree = ""; }; 104 | A76D592821494DCB0091E347 /* MPPhotosAuthorizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPhotosAuthorizer.h; sourceTree = ""; }; 105 | A76D592921494DCB0091E347 /* MPPhotosAuthorizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPhotosAuthorizer.m; sourceTree = ""; }; 106 | A76D593521496DE40091E347 /* MPContactsAuthorization.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPContactsAuthorization.h; sourceTree = ""; }; 107 | A76D593621496DE40091E347 /* MPContactsAuthorization.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPContactsAuthorization.m; sourceTree = ""; }; 108 | /* End PBXFileReference section */ 109 | 110 | /* Begin PBXFrameworksBuildPhase section */ 111 | 30093F5221C1522F004FD64E /* Frameworks */ = { 112 | isa = PBXFrameworksBuildPhase; 113 | buildActionMask = 2147483647; 114 | files = ( 115 | 30093F5321C1522F004FD64E /* PermissionsKit.framework in Frameworks */, 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | A706EB5B214938530098836A /* Frameworks */ = { 120 | isa = PBXFrameworksBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | ); 124 | runOnlyForDeploymentPostprocessing = 0; 125 | }; 126 | A706EB6A214939650098836A /* Frameworks */ = { 127 | isa = PBXFrameworksBuildPhase; 128 | buildActionMask = 2147483647; 129 | files = ( 130 | A76D592D21495A960091E347 /* PermissionsKit.framework in Frameworks */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXFrameworksBuildPhase section */ 135 | 136 | /* Begin PBXGroup section */ 137 | 30093FD321C156F2004FD64E /* Entitlements */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 30093F5D21C15244004FD64E /* PermissionsKitTestApp-Sandboxed.entitlements */, 141 | ); 142 | path = Entitlements; 143 | sourceTree = ""; 144 | }; 145 | A706EB54214938530098836A = { 146 | isa = PBXGroup; 147 | children = ( 148 | A706EB6E214939650098836A /* PermissionsKitTestApp */, 149 | A706EB60214938530098836A /* PermissionsKit */, 150 | A706EB5F214938530098836A /* Products */, 151 | 30093F5C21C1522F004FD64E /* PermissionsKitTestApp copy-Info.plist */, 152 | ); 153 | sourceTree = ""; 154 | }; 155 | A706EB5F214938530098836A /* Products */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | A706EB5E214938530098836A /* PermissionsKit.framework */, 159 | A706EB6D214939650098836A /* PermissionsKitTestApp.app */, 160 | 30093F5B21C1522F004FD64E /* PermissionsKitTestApp-Sandboxed.app */, 161 | ); 162 | name = Products; 163 | sourceTree = ""; 164 | }; 165 | A706EB60214938530098836A /* PermissionsKit */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | A76D590421493C4C0091E347 /* Private */, 169 | A76D590321493C440091E347 /* Public */, 170 | A706EB61214938530098836A /* PermissionsKit.h */, 171 | A706EB62214938530098836A /* Info.plist */, 172 | ); 173 | path = PermissionsKit; 174 | sourceTree = ""; 175 | }; 176 | A706EB6E214939650098836A /* PermissionsKitTestApp */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 30093FD321C156F2004FD64E /* Entitlements */, 180 | A706EB6F214939650098836A /* AppDelegate.h */, 181 | A706EB70214939650098836A /* AppDelegate.m */, 182 | A706EB74214939660098836A /* MainMenu.xib */, 183 | A706EB77214939660098836A /* Info.plist */, 184 | A706EB78214939660098836A /* main.m */, 185 | ); 186 | path = PermissionsKitTestApp; 187 | sourceTree = ""; 188 | }; 189 | A76D590321493C440091E347 /* Public */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | A76D590A21493CDB0091E347 /* MPAuthorizationStatus.h */, 193 | A76D590921493CA70091E347 /* MPPermissionType.h */, 194 | A76D590521493C5C0091E347 /* MPPermissionsKit.h */, 195 | A76D590621493C5C0091E347 /* MPPermissionsKit.m */, 196 | ); 197 | path = Public; 198 | sourceTree = ""; 199 | }; 200 | A76D590421493C4C0091E347 /* Private */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | A76D592721494DC00091E347 /* Photos */, 204 | A76D591E214948410091E347 /* FullDiskAccess */, 205 | A76D5914214941B60091E347 /* Calendar */, 206 | A76D590F21493F1B0091E347 /* Contacts */, 207 | A76D590D21493EB00091E347 /* MPAuthorizer.h */, 208 | ); 209 | path = Private; 210 | sourceTree = ""; 211 | }; 212 | A76D590F21493F1B0091E347 /* Contacts */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | A76D591021493F440091E347 /* MPContactsAuthorizer.h */, 216 | A76D591121493F440091E347 /* MPContactsAuthorizer.m */, 217 | A76D593521496DE40091E347 /* MPContactsAuthorization.h */, 218 | A76D593621496DE40091E347 /* MPContactsAuthorization.m */, 219 | ); 220 | path = Contacts; 221 | sourceTree = ""; 222 | }; 223 | A76D5914214941B60091E347 /* Calendar */ = { 224 | isa = PBXGroup; 225 | children = ( 226 | A76D5915214941CB0091E347 /* MPCalendarAuthorizer.h */, 227 | A76D5916214941CB0091E347 /* MPCalendarAuthorizer.m */, 228 | ); 229 | path = Calendar; 230 | sourceTree = ""; 231 | }; 232 | A76D591E214948410091E347 /* FullDiskAccess */ = { 233 | isa = PBXGroup; 234 | children = ( 235 | A76D591F214948D40091E347 /* MPFullDiskAccessAuthorizer.h */, 236 | A76D5920214948D40091E347 /* MPFullDiskAccessAuthorizer.m */, 237 | ); 238 | path = FullDiskAccess; 239 | sourceTree = ""; 240 | }; 241 | A76D592721494DC00091E347 /* Photos */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | A76D592821494DCB0091E347 /* MPPhotosAuthorizer.h */, 245 | A76D592921494DCB0091E347 /* MPPhotosAuthorizer.m */, 246 | ); 247 | path = Photos; 248 | sourceTree = ""; 249 | }; 250 | /* End PBXGroup section */ 251 | 252 | /* Begin PBXHeadersBuildPhase section */ 253 | A706EB59214938530098836A /* Headers */ = { 254 | isa = PBXHeadersBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | A76D590E21493EB00091E347 /* MPAuthorizer.h in Headers */, 258 | A76D590C21493D4B0091E347 /* MPPermissionType.h in Headers */, 259 | A76D590B21493D480091E347 /* MPAuthorizationStatus.h in Headers */, 260 | A76D591221493F440091E347 /* MPContactsAuthorizer.h in Headers */, 261 | A76D592A21494DCB0091E347 /* MPPhotosAuthorizer.h in Headers */, 262 | A76D5921214948D40091E347 /* MPFullDiskAccessAuthorizer.h in Headers */, 263 | A76D593721496DE40091E347 /* MPContactsAuthorization.h in Headers */, 264 | A706EB63214938530098836A /* PermissionsKit.h in Headers */, 265 | A76D590721493C5C0091E347 /* MPPermissionsKit.h in Headers */, 266 | A76D5917214941CB0091E347 /* MPCalendarAuthorizer.h in Headers */, 267 | ); 268 | runOnlyForDeploymentPostprocessing = 0; 269 | }; 270 | /* End PBXHeadersBuildPhase section */ 271 | 272 | /* Begin PBXNativeTarget section */ 273 | 30093F4C21C1522F004FD64E /* PermissionsKitTestApp-Sandboxed */ = { 274 | isa = PBXNativeTarget; 275 | buildConfigurationList = 30093F5821C1522F004FD64E /* Build configuration list for PBXNativeTarget "PermissionsKitTestApp-Sandboxed" */; 276 | buildPhases = ( 277 | 30093F4F21C1522F004FD64E /* Sources */, 278 | 30093F5221C1522F004FD64E /* Frameworks */, 279 | 30093F5421C1522F004FD64E /* Resources */, 280 | 30093F5621C1522F004FD64E /* Embed Frameworks */, 281 | ); 282 | buildRules = ( 283 | ); 284 | dependencies = ( 285 | 30093F4D21C1522F004FD64E /* PBXTargetDependency */, 286 | ); 287 | name = "PermissionsKitTestApp-Sandboxed"; 288 | productName = PermissionsKitTestApp; 289 | productReference = 30093F5B21C1522F004FD64E /* PermissionsKitTestApp-Sandboxed.app */; 290 | productType = "com.apple.product-type.application"; 291 | }; 292 | A706EB5D214938530098836A /* PermissionsKit */ = { 293 | isa = PBXNativeTarget; 294 | buildConfigurationList = A706EB66214938530098836A /* Build configuration list for PBXNativeTarget "PermissionsKit" */; 295 | buildPhases = ( 296 | A706EB59214938530098836A /* Headers */, 297 | A706EB5A214938530098836A /* Sources */, 298 | A706EB5B214938530098836A /* Frameworks */, 299 | A706EB5C214938530098836A /* Resources */, 300 | ); 301 | buildRules = ( 302 | ); 303 | dependencies = ( 304 | ); 305 | name = PermissionsKit; 306 | productName = PermissionsKit; 307 | productReference = A706EB5E214938530098836A /* PermissionsKit.framework */; 308 | productType = "com.apple.product-type.framework"; 309 | }; 310 | A706EB6C214939650098836A /* PermissionsKitTestApp */ = { 311 | isa = PBXNativeTarget; 312 | buildConfigurationList = A706EB7D214939660098836A /* Build configuration list for PBXNativeTarget "PermissionsKitTestApp" */; 313 | buildPhases = ( 314 | A706EB69214939650098836A /* Sources */, 315 | A706EB6A214939650098836A /* Frameworks */, 316 | A706EB6B214939650098836A /* Resources */, 317 | A76D592F21495A960091E347 /* Embed Frameworks */, 318 | ); 319 | buildRules = ( 320 | ); 321 | dependencies = ( 322 | A706EB7F21493A1A0098836A /* PBXTargetDependency */, 323 | ); 324 | name = PermissionsKitTestApp; 325 | productName = PermissionsKitTestApp; 326 | productReference = A706EB6D214939650098836A /* PermissionsKitTestApp.app */; 327 | productType = "com.apple.product-type.application"; 328 | }; 329 | /* End PBXNativeTarget section */ 330 | 331 | /* Begin PBXProject section */ 332 | A706EB55214938530098836A /* Project object */ = { 333 | isa = PBXProject; 334 | attributes = { 335 | LastUpgradeCheck = 1230; 336 | ORGANIZATIONNAME = MacPaw; 337 | TargetAttributes = { 338 | 30093F4C21C1522F004FD64E = { 339 | SystemCapabilities = { 340 | com.apple.Sandbox = { 341 | enabled = 1; 342 | }; 343 | }; 344 | }; 345 | A706EB5D214938530098836A = { 346 | CreatedOnToolsVersion = 10.0; 347 | }; 348 | A706EB6C214939650098836A = { 349 | CreatedOnToolsVersion = 10.0; 350 | SystemCapabilities = { 351 | com.apple.HardenedRuntime = { 352 | enabled = 0; 353 | }; 354 | com.apple.Sandbox = { 355 | enabled = 0; 356 | }; 357 | }; 358 | }; 359 | }; 360 | }; 361 | buildConfigurationList = A706EB58214938530098836A /* Build configuration list for PBXProject "PermissionsKit" */; 362 | compatibilityVersion = "Xcode 9.3"; 363 | developmentRegion = en; 364 | hasScannedForEncodings = 0; 365 | knownRegions = ( 366 | en, 367 | Base, 368 | ); 369 | mainGroup = A706EB54214938530098836A; 370 | productRefGroup = A706EB5F214938530098836A /* Products */; 371 | projectDirPath = ""; 372 | projectRoot = ""; 373 | targets = ( 374 | A706EB5D214938530098836A /* PermissionsKit */, 375 | A706EB6C214939650098836A /* PermissionsKitTestApp */, 376 | 30093F4C21C1522F004FD64E /* PermissionsKitTestApp-Sandboxed */, 377 | ); 378 | }; 379 | /* End PBXProject section */ 380 | 381 | /* Begin PBXResourcesBuildPhase section */ 382 | 30093F5421C1522F004FD64E /* Resources */ = { 383 | isa = PBXResourcesBuildPhase; 384 | buildActionMask = 2147483647; 385 | files = ( 386 | 30093F5521C1522F004FD64E /* MainMenu.xib in Resources */, 387 | ); 388 | runOnlyForDeploymentPostprocessing = 0; 389 | }; 390 | A706EB5C214938530098836A /* Resources */ = { 391 | isa = PBXResourcesBuildPhase; 392 | buildActionMask = 2147483647; 393 | files = ( 394 | ); 395 | runOnlyForDeploymentPostprocessing = 0; 396 | }; 397 | A706EB6B214939650098836A /* Resources */ = { 398 | isa = PBXResourcesBuildPhase; 399 | buildActionMask = 2147483647; 400 | files = ( 401 | A706EB76214939660098836A /* MainMenu.xib in Resources */, 402 | ); 403 | runOnlyForDeploymentPostprocessing = 0; 404 | }; 405 | /* End PBXResourcesBuildPhase section */ 406 | 407 | /* Begin PBXSourcesBuildPhase section */ 408 | 30093F4F21C1522F004FD64E /* Sources */ = { 409 | isa = PBXSourcesBuildPhase; 410 | buildActionMask = 2147483647; 411 | files = ( 412 | 30093F5021C1522F004FD64E /* main.m in Sources */, 413 | 30093F5121C1522F004FD64E /* AppDelegate.m in Sources */, 414 | ); 415 | runOnlyForDeploymentPostprocessing = 0; 416 | }; 417 | A706EB5A214938530098836A /* Sources */ = { 418 | isa = PBXSourcesBuildPhase; 419 | buildActionMask = 2147483647; 420 | files = ( 421 | A76D591321493F440091E347 /* MPContactsAuthorizer.m in Sources */, 422 | A76D5922214948D40091E347 /* MPFullDiskAccessAuthorizer.m in Sources */, 423 | A76D592B21494DCB0091E347 /* MPPhotosAuthorizer.m in Sources */, 424 | A76D593821496DE40091E347 /* MPContactsAuthorization.m in Sources */, 425 | A76D590821493C5C0091E347 /* MPPermissionsKit.m in Sources */, 426 | A76D5918214941CB0091E347 /* MPCalendarAuthorizer.m in Sources */, 427 | ); 428 | runOnlyForDeploymentPostprocessing = 0; 429 | }; 430 | A706EB69214939650098836A /* Sources */ = { 431 | isa = PBXSourcesBuildPhase; 432 | buildActionMask = 2147483647; 433 | files = ( 434 | A706EB79214939660098836A /* main.m in Sources */, 435 | A706EB71214939650098836A /* AppDelegate.m in Sources */, 436 | ); 437 | runOnlyForDeploymentPostprocessing = 0; 438 | }; 439 | /* End PBXSourcesBuildPhase section */ 440 | 441 | /* Begin PBXTargetDependency section */ 442 | 30093F4D21C1522F004FD64E /* PBXTargetDependency */ = { 443 | isa = PBXTargetDependency; 444 | target = A706EB5D214938530098836A /* PermissionsKit */; 445 | targetProxy = 30093F4E21C1522F004FD64E /* PBXContainerItemProxy */; 446 | }; 447 | A706EB7F21493A1A0098836A /* PBXTargetDependency */ = { 448 | isa = PBXTargetDependency; 449 | target = A706EB5D214938530098836A /* PermissionsKit */; 450 | targetProxy = A706EB7E21493A1A0098836A /* PBXContainerItemProxy */; 451 | }; 452 | /* End PBXTargetDependency section */ 453 | 454 | /* Begin PBXVariantGroup section */ 455 | A706EB74214939660098836A /* MainMenu.xib */ = { 456 | isa = PBXVariantGroup; 457 | children = ( 458 | A706EB75214939660098836A /* Base */, 459 | ); 460 | name = MainMenu.xib; 461 | sourceTree = ""; 462 | }; 463 | /* End PBXVariantGroup section */ 464 | 465 | /* Begin XCBuildConfiguration section */ 466 | 30093F5921C1522F004FD64E /* Debug */ = { 467 | isa = XCBuildConfiguration; 468 | buildSettings = { 469 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 470 | CODE_SIGN_ENTITLEMENTS = "PermissionsKitTestApp/Entitlements/PermissionsKitTestApp-Sandboxed.entitlements"; 471 | CODE_SIGN_IDENTITY = "-"; 472 | CODE_SIGN_STYLE = Automatic; 473 | COMBINE_HIDPI_IMAGES = YES; 474 | DEVELOPMENT_TEAM = S8EX82NJP6; 475 | INFOPLIST_FILE = "PermissionsKitTestApp copy-Info.plist"; 476 | LD_RUNPATH_SEARCH_PATHS = ( 477 | "$(inherited)", 478 | "@executable_path/../Frameworks", 479 | ); 480 | PRODUCT_BUNDLE_IDENTIFIER = "com.macpaw.PermissionsKitTestApp-sandboxed"; 481 | PRODUCT_NAME = "$(TARGET_NAME)"; 482 | }; 483 | name = Debug; 484 | }; 485 | 30093F5A21C1522F004FD64E /* Release */ = { 486 | isa = XCBuildConfiguration; 487 | buildSettings = { 488 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 489 | CODE_SIGN_ENTITLEMENTS = "PermissionsKitTestApp/Entitlements/PermissionsKitTestApp-Sandboxed.entitlements"; 490 | CODE_SIGN_IDENTITY = "-"; 491 | CODE_SIGN_STYLE = Automatic; 492 | COMBINE_HIDPI_IMAGES = YES; 493 | DEVELOPMENT_TEAM = S8EX82NJP6; 494 | INFOPLIST_FILE = "PermissionsKitTestApp copy-Info.plist"; 495 | LD_RUNPATH_SEARCH_PATHS = ( 496 | "$(inherited)", 497 | "@executable_path/../Frameworks", 498 | ); 499 | PRODUCT_BUNDLE_IDENTIFIER = "com.macpaw.PermissionsKitTestApp-sandboxed"; 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | }; 502 | name = Release; 503 | }; 504 | A706EB64214938530098836A /* Debug */ = { 505 | isa = XCBuildConfiguration; 506 | buildSettings = { 507 | ALWAYS_SEARCH_USER_PATHS = NO; 508 | CLANG_ANALYZER_NONNULL = YES; 509 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 510 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 511 | CLANG_CXX_LIBRARY = "libc++"; 512 | CLANG_ENABLE_MODULES = YES; 513 | CLANG_ENABLE_OBJC_ARC = YES; 514 | CLANG_ENABLE_OBJC_WEAK = YES; 515 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 516 | CLANG_WARN_BOOL_CONVERSION = YES; 517 | CLANG_WARN_COMMA = YES; 518 | CLANG_WARN_CONSTANT_CONVERSION = YES; 519 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 520 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 521 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 522 | CLANG_WARN_EMPTY_BODY = YES; 523 | CLANG_WARN_ENUM_CONVERSION = YES; 524 | CLANG_WARN_INFINITE_RECURSION = YES; 525 | CLANG_WARN_INT_CONVERSION = YES; 526 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 527 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 528 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 529 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 530 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 531 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 532 | CLANG_WARN_STRICT_PROTOTYPES = YES; 533 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 534 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 535 | CLANG_WARN_UNREACHABLE_CODE = YES; 536 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 537 | CODE_SIGN_IDENTITY = "Mac Developer"; 538 | COPY_PHASE_STRIP = NO; 539 | CURRENT_PROJECT_VERSION = 1.0.6; 540 | DEBUG_INFORMATION_FORMAT = dwarf; 541 | ENABLE_STRICT_OBJC_MSGSEND = YES; 542 | ENABLE_TESTABILITY = YES; 543 | GCC_C_LANGUAGE_STANDARD = gnu11; 544 | GCC_DYNAMIC_NO_PIC = NO; 545 | GCC_NO_COMMON_BLOCKS = YES; 546 | GCC_OPTIMIZATION_LEVEL = 0; 547 | GCC_PREPROCESSOR_DEFINITIONS = ( 548 | "DEBUG=1", 549 | "$(inherited)", 550 | ); 551 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 552 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 553 | GCC_WARN_UNDECLARED_SELECTOR = YES; 554 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 555 | GCC_WARN_UNUSED_FUNCTION = YES; 556 | GCC_WARN_UNUSED_VARIABLE = YES; 557 | MACOSX_DEPLOYMENT_TARGET = 10.13; 558 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 559 | ONLY_ACTIVE_ARCH = YES; 560 | SDKROOT = macosx; 561 | VERSIONING_SYSTEM = "apple-generic"; 562 | VERSION_INFO_PREFIX = ""; 563 | }; 564 | name = Debug; 565 | }; 566 | A706EB65214938530098836A /* Release */ = { 567 | isa = XCBuildConfiguration; 568 | buildSettings = { 569 | ALWAYS_SEARCH_USER_PATHS = NO; 570 | CLANG_ANALYZER_NONNULL = YES; 571 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 572 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 573 | CLANG_CXX_LIBRARY = "libc++"; 574 | CLANG_ENABLE_MODULES = YES; 575 | CLANG_ENABLE_OBJC_ARC = YES; 576 | CLANG_ENABLE_OBJC_WEAK = YES; 577 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 578 | CLANG_WARN_BOOL_CONVERSION = YES; 579 | CLANG_WARN_COMMA = YES; 580 | CLANG_WARN_CONSTANT_CONVERSION = YES; 581 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 582 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 583 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 584 | CLANG_WARN_EMPTY_BODY = YES; 585 | CLANG_WARN_ENUM_CONVERSION = YES; 586 | CLANG_WARN_INFINITE_RECURSION = YES; 587 | CLANG_WARN_INT_CONVERSION = YES; 588 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 589 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 590 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 591 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 592 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 593 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 594 | CLANG_WARN_STRICT_PROTOTYPES = YES; 595 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 596 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 597 | CLANG_WARN_UNREACHABLE_CODE = YES; 598 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 599 | CODE_SIGN_IDENTITY = "Mac Developer"; 600 | COPY_PHASE_STRIP = NO; 601 | CURRENT_PROJECT_VERSION = 1.0.6; 602 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 603 | ENABLE_NS_ASSERTIONS = NO; 604 | ENABLE_STRICT_OBJC_MSGSEND = YES; 605 | GCC_C_LANGUAGE_STANDARD = gnu11; 606 | GCC_NO_COMMON_BLOCKS = YES; 607 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 608 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 609 | GCC_WARN_UNDECLARED_SELECTOR = YES; 610 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 611 | GCC_WARN_UNUSED_FUNCTION = YES; 612 | GCC_WARN_UNUSED_VARIABLE = YES; 613 | MACOSX_DEPLOYMENT_TARGET = 10.13; 614 | MTL_ENABLE_DEBUG_INFO = NO; 615 | SDKROOT = macosx; 616 | VERSIONING_SYSTEM = "apple-generic"; 617 | VERSION_INFO_PREFIX = ""; 618 | }; 619 | name = Release; 620 | }; 621 | A706EB67214938530098836A /* Debug */ = { 622 | isa = XCBuildConfiguration; 623 | buildSettings = { 624 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 625 | CODE_SIGN_IDENTITY = ""; 626 | CODE_SIGN_STYLE = Manual; 627 | COMBINE_HIDPI_IMAGES = YES; 628 | DEFINES_MODULE = YES; 629 | DEVELOPMENT_TEAM = ""; 630 | DYLIB_COMPATIBILITY_VERSION = 1; 631 | DYLIB_CURRENT_VERSION = "$(CURRENT_PROJECT_VERSION)"; 632 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 633 | FRAMEWORK_VERSION = A; 634 | INFOPLIST_FILE = PermissionsKit/Info.plist; 635 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 636 | LD_RUNPATH_SEARCH_PATHS = ( 637 | "$(inherited)", 638 | "@executable_path/../Frameworks", 639 | "@loader_path/Frameworks", 640 | ); 641 | PRODUCT_BUNDLE_IDENTIFIER = com.macpaw.PermissionsKit; 642 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 643 | PROVISIONING_PROFILE_SPECIFIER = ""; 644 | SKIP_INSTALL = YES; 645 | }; 646 | name = Debug; 647 | }; 648 | A706EB68214938530098836A /* Release */ = { 649 | isa = XCBuildConfiguration; 650 | buildSettings = { 651 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 652 | CODE_SIGN_IDENTITY = ""; 653 | CODE_SIGN_STYLE = Manual; 654 | COMBINE_HIDPI_IMAGES = YES; 655 | DEFINES_MODULE = YES; 656 | DEVELOPMENT_TEAM = ""; 657 | DYLIB_COMPATIBILITY_VERSION = 1; 658 | DYLIB_CURRENT_VERSION = "$(CURRENT_PROJECT_VERSION)"; 659 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 660 | FRAMEWORK_VERSION = A; 661 | INFOPLIST_FILE = PermissionsKit/Info.plist; 662 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 663 | LD_RUNPATH_SEARCH_PATHS = ( 664 | "$(inherited)", 665 | "@executable_path/../Frameworks", 666 | "@loader_path/Frameworks", 667 | ); 668 | PRODUCT_BUNDLE_IDENTIFIER = com.macpaw.PermissionsKit; 669 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 670 | PROVISIONING_PROFILE_SPECIFIER = ""; 671 | SKIP_INSTALL = YES; 672 | }; 673 | name = Release; 674 | }; 675 | A706EB7B214939660098836A /* Debug */ = { 676 | isa = XCBuildConfiguration; 677 | buildSettings = { 678 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 679 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 680 | CODE_SIGN_IDENTITY = "-"; 681 | CODE_SIGN_STYLE = Automatic; 682 | COMBINE_HIDPI_IMAGES = YES; 683 | DEVELOPMENT_TEAM = S8EX82NJP6; 684 | INFOPLIST_FILE = PermissionsKitTestApp/Info.plist; 685 | LD_RUNPATH_SEARCH_PATHS = ( 686 | "$(inherited)", 687 | "@executable_path/../Frameworks", 688 | ); 689 | PRODUCT_BUNDLE_IDENTIFIER = com.macpaw.PermissionsKitTestApp; 690 | PRODUCT_NAME = "$(TARGET_NAME)"; 691 | }; 692 | name = Debug; 693 | }; 694 | A706EB7C214939660098836A /* Release */ = { 695 | isa = XCBuildConfiguration; 696 | buildSettings = { 697 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 698 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 699 | CODE_SIGN_IDENTITY = "-"; 700 | CODE_SIGN_STYLE = Automatic; 701 | COMBINE_HIDPI_IMAGES = YES; 702 | DEVELOPMENT_TEAM = S8EX82NJP6; 703 | INFOPLIST_FILE = PermissionsKitTestApp/Info.plist; 704 | LD_RUNPATH_SEARCH_PATHS = ( 705 | "$(inherited)", 706 | "@executable_path/../Frameworks", 707 | ); 708 | PRODUCT_BUNDLE_IDENTIFIER = com.macpaw.PermissionsKitTestApp; 709 | PRODUCT_NAME = "$(TARGET_NAME)"; 710 | }; 711 | name = Release; 712 | }; 713 | /* End XCBuildConfiguration section */ 714 | 715 | /* Begin XCConfigurationList section */ 716 | 30093F5821C1522F004FD64E /* Build configuration list for PBXNativeTarget "PermissionsKitTestApp-Sandboxed" */ = { 717 | isa = XCConfigurationList; 718 | buildConfigurations = ( 719 | 30093F5921C1522F004FD64E /* Debug */, 720 | 30093F5A21C1522F004FD64E /* Release */, 721 | ); 722 | defaultConfigurationIsVisible = 0; 723 | defaultConfigurationName = Release; 724 | }; 725 | A706EB58214938530098836A /* Build configuration list for PBXProject "PermissionsKit" */ = { 726 | isa = XCConfigurationList; 727 | buildConfigurations = ( 728 | A706EB64214938530098836A /* Debug */, 729 | A706EB65214938530098836A /* Release */, 730 | ); 731 | defaultConfigurationIsVisible = 0; 732 | defaultConfigurationName = Release; 733 | }; 734 | A706EB66214938530098836A /* Build configuration list for PBXNativeTarget "PermissionsKit" */ = { 735 | isa = XCConfigurationList; 736 | buildConfigurations = ( 737 | A706EB67214938530098836A /* Debug */, 738 | A706EB68214938530098836A /* Release */, 739 | ); 740 | defaultConfigurationIsVisible = 0; 741 | defaultConfigurationName = Release; 742 | }; 743 | A706EB7D214939660098836A /* Build configuration list for PBXNativeTarget "PermissionsKitTestApp" */ = { 744 | isa = XCConfigurationList; 745 | buildConfigurations = ( 746 | A706EB7B214939660098836A /* Debug */, 747 | A706EB7C214939660098836A /* Release */, 748 | ); 749 | defaultConfigurationIsVisible = 0; 750 | defaultConfigurationName = Release; 751 | }; 752 | /* End XCConfigurationList section */ 753 | }; 754 | rootObject = A706EB55214938530098836A /* Project object */; 755 | } 756 | -------------------------------------------------------------------------------- /PermissionsKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PermissionsKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PermissionsKit.xcodeproj/xcshareddata/xcschemes/PermissionsKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /PermissionsKit/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.6 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2018 MacPaw. All rights reserved. 23 | 24 | 25 | -------------------------------------------------------------------------------- /PermissionsKit/PermissionsKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // PermissionsKit.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Cocoa; 10 | 11 | FOUNDATION_EXPORT double PermissionsKitVersionNumber; 12 | FOUNDATION_EXPORT const unsigned char PermissionsKitVersionString[]; 13 | 14 | #import 15 | #import 16 | #import 17 | -------------------------------------------------------------------------------- /PermissionsKit/Private/Calendar/MPCalendarAuthorizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPCalendarAuthorizer.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | #import "MPAuthorizer.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface MPCalendarAuthorizer : NSObject 16 | 17 | + (instancetype)events; 18 | + (instancetype)reminders; 19 | 20 | @end 21 | 22 | @interface MPCalendarAuthorizer(Unavailable) 23 | 24 | - (instancetype)init NS_UNAVAILABLE; 25 | + (instancetype)new NS_UNAVAILABLE; 26 | 27 | @end 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /PermissionsKit/Private/Calendar/MPCalendarAuthorizer.m: -------------------------------------------------------------------------------- 1 | // 2 | // MPCalendarAuthorizer.m 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import EventKit; 10 | 11 | #import "MPCalendarAuthorizer.h" 12 | 13 | @interface MPCalendarAuthorizer () 14 | 15 | @property (nonatomic) EKEntityType entityType; 16 | 17 | @end 18 | 19 | @implementation MPCalendarAuthorizer 20 | 21 | + (instancetype)events 22 | { 23 | return [[self alloc] initWithEntityType:EKEntityTypeEvent]; 24 | } 25 | 26 | + (instancetype)reminders 27 | { 28 | return [[self alloc] initWithEntityType:EKEntityTypeReminder]; 29 | } 30 | 31 | - (instancetype)initWithEntityType:(EKEntityType)entityType 32 | { 33 | self = [super init]; 34 | if (self) 35 | { 36 | _entityType = entityType; 37 | } 38 | return self; 39 | } 40 | 41 | #pragma mark - Public 42 | 43 | - (MPAuthorizationStatus)authorizationStatus 44 | { 45 | EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:self.entityType]; 46 | return [self _authorizationStatusFromCalendarAuthorizationStatus:status]; 47 | } 48 | 49 | - (void)requestAuthorizationWithCompletion:(nonnull void (^)(MPAuthorizationStatus))completionHandler 50 | { 51 | EKEventStore *store = [EKEventStore new]; 52 | [store requestAccessToEntityType:self.entityType completion:^(BOOL granted, NSError * _Nullable error) { 53 | completionHandler(granted ? MPAuthorizationStatusAuthorized : MPAuthorizationStatusDenied); 54 | }]; 55 | } 56 | 57 | #pragma mark - Private 58 | 59 | - (MPAuthorizationStatus)_authorizationStatusFromCalendarAuthorizationStatus:(EKAuthorizationStatus)status 60 | { 61 | switch (status) { 62 | case EKAuthorizationStatusDenied: 63 | case EKAuthorizationStatusRestricted: 64 | return MPAuthorizationStatusDenied; 65 | case EKAuthorizationStatusAuthorized: 66 | return MPAuthorizationStatusAuthorized; 67 | case EKAuthorizationStatusNotDetermined: 68 | case EKAuthorizationStatusWriteOnly: 69 | return MPAuthorizationStatusNotDetermined; 70 | } 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /PermissionsKit/Private/Contacts/MPContactsAuthorization.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPContactsAuthorization.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | @import Contacts; 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface MPContactsAuthorization : NSObject 15 | 16 | + (CNAuthorizationStatus)authorizationStatusForEntityType:(CNEntityType)entityType API_AVAILABLE(macos(10.11)); 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /PermissionsKit/Private/Contacts/MPContactsAuthorization.m: -------------------------------------------------------------------------------- 1 | // 2 | // MPContactsAuthorization.m 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | #import "MPContactsAuthorization.h" 10 | 11 | @implementation MPContactsAuthorization 12 | 13 | + (CNAuthorizationStatus)authorizationStatusForEntityType:(CNEntityType)entityType 14 | { 15 | id authorization = NSClassFromString(@"CNAuthorization"); 16 | if ([authorization respondsToSelector:@selector(authorizationStatusForEntityType:)]) 17 | { 18 | return [authorization authorizationStatusForEntityType:entityType]; 19 | } 20 | else 21 | { 22 | return [CNContactStore authorizationStatusForEntityType:entityType]; 23 | } 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /PermissionsKit/Private/Contacts/MPContactsAuthorizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPContactsAuthorizer.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | #import "MPAuthorizer.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface MPContactsAuthorizer : NSObject 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /PermissionsKit/Private/Contacts/MPContactsAuthorizer.m: -------------------------------------------------------------------------------- 1 | // 2 | // MPContactsAuthorizer.m 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Contacts; 10 | 11 | #import "MPContactsAuthorizer.h" 12 | #import "MPContactsAuthorization.h" 13 | 14 | @implementation MPContactsAuthorizer 15 | 16 | - (MPAuthorizationStatus)authorizationStatus 17 | { 18 | if (@available(macOS 10.11, *)) 19 | { 20 | //rdar://34158737 21 | CNAuthorizationStatus authorizationStatus = [MPContactsAuthorization authorizationStatusForEntityType:CNEntityTypeContacts]; 22 | return [self _authorizationStatusFromContactsAuthorizationStatus:authorizationStatus]; 23 | } 24 | else 25 | { 26 | return MPAuthorizationStatusAuthorized; 27 | } 28 | } 29 | 30 | - (void)requestAuthorizationWithCompletion:(nonnull void (^)(MPAuthorizationStatus))completionHandler 31 | { 32 | if (@available(macOS 10.11, *)) 33 | { 34 | CNContactStore *store = [CNContactStore new]; 35 | [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { 36 | completionHandler(granted ? MPAuthorizationStatusAuthorized : MPAuthorizationStatusDenied); 37 | }]; 38 | } 39 | else 40 | { 41 | completionHandler(MPAuthorizationStatusAuthorized); 42 | } 43 | } 44 | 45 | #pragma mark - Private 46 | 47 | - (MPAuthorizationStatus)_authorizationStatusFromContactsAuthorizationStatus:(CNAuthorizationStatus)status 48 | API_AVAILABLE(macos(10.11)){ 49 | switch (status) { 50 | case CNAuthorizationStatusDenied: 51 | case CNAuthorizationStatusRestricted: 52 | return MPAuthorizationStatusDenied; 53 | case CNAuthorizationStatusAuthorized: 54 | return MPAuthorizationStatusAuthorized; 55 | case CNAuthorizationStatusNotDetermined: 56 | return MPAuthorizationStatusNotDetermined; 57 | } 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /PermissionsKit/Private/FullDiskAccess/MPFullDiskAccessAuthorizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPFullDiskAccessAuthorizer.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import AppKit; 10 | 11 | #import "MPAuthorizer.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface MPFullDiskAccessAuthorizer : NSObject 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /PermissionsKit/Private/FullDiskAccess/MPFullDiskAccessAuthorizer.m: -------------------------------------------------------------------------------- 1 | // 2 | // MPFullDiskAccessAuthorizer.m 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | #import "MPFullDiskAccessAuthorizer.h" 10 | #import 11 | 12 | @interface MPFullDiskAccessAuthorizer() 13 | 14 | @property (nonatomic, strong) NSFileManager *fileManager; 15 | @property (nonatomic, strong) NSWorkspace *workspace; 16 | @property (nonatomic, copy) NSString *userHomeFolderPath; 17 | 18 | @end 19 | 20 | @implementation MPFullDiskAccessAuthorizer 21 | 22 | - (instancetype)initWithFileManager:(NSFileManager *)fileManager workspace:(NSWorkspace *)workspace 23 | { 24 | self = [super init]; 25 | if (self) 26 | { 27 | _fileManager = fileManager; 28 | _workspace = workspace; 29 | } 30 | return self; 31 | } 32 | 33 | - (instancetype)init 34 | { 35 | return [self initWithFileManager:[NSFileManager defaultManager] workspace:[NSWorkspace sharedWorkspace]]; 36 | } 37 | 38 | #pragma mark - Public 39 | 40 | - (MPAuthorizationStatus)authorizationStatus 41 | { 42 | if (@available(macOS 10.14, *)) 43 | { 44 | return [self _fullDiskAuthorizationStatus]; 45 | } 46 | else 47 | { 48 | return MPAuthorizationStatusAuthorized; 49 | } 50 | } 51 | 52 | - (void)requestAuthorizationWithCompletion:(nonnull void (^)(MPAuthorizationStatus))completionHandler 53 | { 54 | if (@available(macOS 10.14, *)) 55 | { 56 | [self _openPreferences]; 57 | } 58 | else 59 | { 60 | completionHandler(MPAuthorizationStatusAuthorized); 61 | } 62 | } 63 | 64 | #pragma mark - Private 65 | 66 | 67 | - (MPAuthorizationStatus)_checkFDAUsingFile:(NSString *)path 68 | { 69 | int fd = open([path cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY); 70 | if (fd != -1) 71 | { 72 | close(fd); 73 | return MPAuthorizationStatusAuthorized; 74 | } 75 | 76 | if (errno == EPERM || errno == EACCES) 77 | { 78 | return MPAuthorizationStatusDenied; 79 | } 80 | 81 | return MPAuthorizationStatusNotDetermined; 82 | } 83 | 84 | - (MPAuthorizationStatus)_fullDiskAuthorizationStatus 85 | { 86 | // We can't use just a single file to test FDA because: 87 | // a) the file might not exist 88 | // b) user might not have access to file even thought FDA is enabled 89 | // Therefore, if any of these files is readable - we have FDA, 90 | // otherwise if any exists, but can't be read, - we don't 91 | NSArray *testFiles = @[ 92 | [self.userHomeFolderPath stringByAppendingPathComponent:@"Library/Safari/CloudTabs.db"], 93 | [self.userHomeFolderPath stringByAppendingPathComponent:@"Library/Safari/Bookmarks.plist"], 94 | [self.userHomeFolderPath stringByAppendingPathComponent: @"Library/Application Support/com.apple.TCC/TCC.db"], 95 | @"/Library/Preferences/com.apple.TimeMachine.plist", 96 | ]; 97 | 98 | MPAuthorizationStatus resultStatus = MPAuthorizationStatusNotDetermined; 99 | for (NSString *file in testFiles) 100 | { 101 | MPAuthorizationStatus status = [self _checkFDAUsingFile: file]; 102 | if (status == MPAuthorizationStatusAuthorized) 103 | { 104 | resultStatus = MPAuthorizationStatusAuthorized; 105 | break; 106 | } 107 | if (status == MPAuthorizationStatusDenied) 108 | { 109 | resultStatus = MPAuthorizationStatusDenied; 110 | } 111 | } 112 | 113 | return resultStatus; 114 | } 115 | 116 | - (NSString *)userHomeFolderPath 117 | { 118 | @synchronized (self) 119 | { 120 | if (!_userHomeFolderPath) 121 | { 122 | BOOL isSandboxed = (nil != NSProcessInfo.processInfo.environment[@"APP_SANDBOX_CONTAINER_ID"]); 123 | if (isSandboxed) 124 | { 125 | struct passwd *pw = getpwuid(getuid()); 126 | assert(pw); 127 | _userHomeFolderPath = [NSString stringWithUTF8String:pw->pw_dir]; 128 | } 129 | else 130 | { 131 | _userHomeFolderPath = NSHomeDirectory(); 132 | } 133 | } 134 | } 135 | return _userHomeFolderPath; 136 | } 137 | 138 | - (void)_openPreferences 139 | { 140 | [self.workspace openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"]]; 141 | } 142 | 143 | @end 144 | -------------------------------------------------------------------------------- /PermissionsKit/Private/MPAuthorizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPAuthorizer.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | #import "MPAuthorizationStatus.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @protocol MPAuthorizer 16 | 17 | - (MPAuthorizationStatus)authorizationStatus; 18 | - (void)requestAuthorizationWithCompletion:(void (^)(MPAuthorizationStatus status))completionHandler; 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /PermissionsKit/Private/Photos/MPPhotosAuthorizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPPhotosAuthorizer.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | #import "MPAuthorizer.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | /** 16 | * Authorizer for Photos library usage. 17 | * @discussion MPPhotosAuthorizer works only for Photos Extensions. 18 | * rdar://34431396 19 | * rdar://43426722 20 | */ 21 | @interface MPPhotosAuthorizer : NSObject 22 | 23 | @end 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /PermissionsKit/Private/Photos/MPPhotosAuthorizer.m: -------------------------------------------------------------------------------- 1 | // 2 | // MPPhotosAuthorizer.m 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Photos; 10 | 11 | #import "MPPhotosAuthorizer.h" 12 | 13 | @implementation MPPhotosAuthorizer 14 | 15 | - (MPAuthorizationStatus)authorizationStatus 16 | { 17 | if (@available(macOS 10.13, *)) 18 | { 19 | PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; 20 | return [self _authorizationStatusFromPhotosAuthorizationStatus:status]; 21 | } 22 | else 23 | { 24 | return MPAuthorizationStatusAuthorized; 25 | } 26 | } 27 | 28 | - (void)requestAuthorizationWithCompletion:(nonnull void (^)(MPAuthorizationStatus))completionHandler 29 | { 30 | if (@available(macOS 10.13, *)) 31 | { 32 | [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { 33 | completionHandler([self _authorizationStatusFromPhotosAuthorizationStatus:status]); 34 | }]; 35 | } 36 | else 37 | { 38 | completionHandler(MPAuthorizationStatusAuthorized); 39 | } 40 | } 41 | 42 | #pragma mark - Private 43 | 44 | - (MPAuthorizationStatus)_authorizationStatusFromPhotosAuthorizationStatus:(PHAuthorizationStatus)status 45 | API_AVAILABLE(macos(10.13)){ 46 | switch (status) { 47 | case PHAuthorizationStatusDenied: 48 | case PHAuthorizationStatusRestricted: 49 | return MPAuthorizationStatusDenied; 50 | case PHAuthorizationStatusAuthorized: 51 | return MPAuthorizationStatusAuthorized; 52 | case PHAuthorizationStatusNotDetermined: 53 | return MPAuthorizationStatusNotDetermined; 54 | case PHAuthorizationStatusLimited: 55 | return MPAuthorizationStatusLimited; 56 | } 57 | return MPAuthorizationStatusDenied; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /PermissionsKit/Public/MPAuthorizationStatus.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPAuthorizationStatus.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | typedef NS_ENUM(NSUInteger, MPAuthorizationStatus) { 10 | MPAuthorizationStatusNotDetermined, 11 | MPAuthorizationStatusDenied, 12 | MPAuthorizationStatusAuthorized, 13 | MPAuthorizationStatusLimited API_AVAILABLE(macos(10.11)) 14 | } NS_SWIFT_NAME(AuthorizationStatus); 15 | -------------------------------------------------------------------------------- /PermissionsKit/Public/MPPermissionType.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPPermissionType.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | typedef NS_ENUM(NSUInteger, MPPermissionType) { 10 | MPPermissionTypeCalendar = 0, 11 | MPPermissionTypeReminders, 12 | MPPermissionTypeContacts, 13 | MPPermissionTypePhotos, 14 | MPPermissionTypeFullDiskAccess 15 | } NS_SWIFT_NAME(PermissionType); 16 | -------------------------------------------------------------------------------- /PermissionsKit/Public/MPPermissionsKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // MPPermissionsKit.h 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | #import 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | NS_SWIFT_NAME(PermissionsKit) 17 | @interface MPPermissionsKit : NSObject 18 | 19 | /** 20 | * Requests current authorization status for a given type. 21 | * 22 | * @discussion It is safe to call this method on system where permission type is not supported. MPAuthorizationStatusAuthorized will be returned. 23 | * 24 | * @param permissionType MPPermissionType 25 | * @return MPAuthorizationStatus 26 | */ 27 | + (MPAuthorizationStatus)authorizationStatusForPermissionType:(MPPermissionType)permissionType; 28 | 29 | /** 30 | * Requests user authorization for a given permission. Completion will be invoked with a user decision. Completion queue is undefined. 31 | * @discussion There will be no completion when requesting MPPermissionTypeFullDiskAccess, because its status is unknown. You should implement your own callback mechanism, for example - polling authorization. It is safe to call this method on system where permission type is not supported. MPAuthorizationStatusAuthorized will be returned. 32 | * 33 | * @param permissionType MPPermissionType 34 | * @param completionHandler void (^)(MPAuthorizationStatus status) 35 | */ 36 | + (void)requestAuthorizationForPermissionType:(MPPermissionType)permissionType withCompletion:(void (^)(MPAuthorizationStatus status))completionHandler; 37 | 38 | @end 39 | 40 | NS_ASSUME_NONNULL_END 41 | -------------------------------------------------------------------------------- /PermissionsKit/Public/MPPermissionsKit.m: -------------------------------------------------------------------------------- 1 | // 2 | // MPPermissionsKit.m 3 | // PermissionsKit 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | #import "MPPermissionsKit.h" 10 | 11 | #import "MPAuthorizer.h" 12 | #import "MPPhotosAuthorizer.h" 13 | #import "MPFullDiskAccessAuthorizer.h" 14 | #import "MPCalendarAuthorizer.h" 15 | #import "MPContactsAuthorizer.h" 16 | 17 | typedef NSDictionary> * MPAuthorizersMap; 18 | 19 | @implementation MPPermissionsKit 20 | 21 | #pragma mark - Public 22 | 23 | + (MPAuthorizationStatus)authorizationStatusForPermissionType:(MPPermissionType)permissionType 24 | { 25 | id authorizer = self.authorizers[@(permissionType)]; 26 | NSAssert(authorizer != nil, @"Could not find authorizer for type %ld", permissionType); 27 | return authorizer.authorizationStatus; 28 | } 29 | 30 | + (void)requestAuthorizationForPermissionType:(MPPermissionType)permissionType withCompletion:(void (^)(MPAuthorizationStatus status))completionHandler 31 | { 32 | id authorizer = self.authorizers[@(permissionType)]; 33 | NSAssert(authorizer != nil, @"Could not find authorizer for type %ld", permissionType); 34 | [authorizer requestAuthorizationWithCompletion:completionHandler]; 35 | } 36 | 37 | #pragma mark - Private 38 | 39 | + (MPAuthorizersMap)authorizers 40 | { 41 | static MPAuthorizersMap map; 42 | static dispatch_once_t onceToken; 43 | dispatch_once(&onceToken, ^{ 44 | map = @{ 45 | @(MPPermissionTypePhotos) : [MPPhotosAuthorizer new], 46 | @(MPPermissionTypeContacts) : [MPContactsAuthorizer new], 47 | @(MPPermissionTypeCalendar) : [MPCalendarAuthorizer events], 48 | @(MPPermissionTypeReminders) : [MPCalendarAuthorizer reminders], 49 | @(MPPermissionTypeFullDiskAccess) : [MPFullDiskAccessAuthorizer new] 50 | }; 51 | }); 52 | return map; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /PermissionsKitTestApp copy-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSCalendarsUsageDescription 26 | Test Description Calendars 27 | NSContactsUsageDescription 28 | Test Description Contacts 29 | NSHumanReadableCopyright 30 | Copyright © 2018 MacPaw. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPhotoLibraryAddUsageDescription 34 | P 35 | NSPhotoLibraryUsageDescription 36 | Photos Desc 37 | NSPrincipalClass 38 | NSApplication 39 | NSRemindersUsageDescription 40 | Test Description Reminders 41 | 42 | 43 | -------------------------------------------------------------------------------- /PermissionsKitTestApp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PermissionsKitTestApp 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /PermissionsKitTestApp/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PermissionsKitTestApp 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import PermissionsKit; 10 | 11 | #import "AppDelegate.h" 12 | 13 | @interface AppDelegate () 14 | 15 | @property (weak) IBOutlet NSWindow *window; 16 | 17 | @property (weak) IBOutlet NSTextField *contactsLabel; 18 | @property (weak) IBOutlet NSTextField *calendarLabel; 19 | @property (weak) IBOutlet NSTextField *remindersLabel; 20 | @property (weak) IBOutlet NSTextField *photosLabel; 21 | @property (weak) IBOutlet NSTextField *fullDiskAccessLabel; 22 | 23 | @property (nonatomic, strong) NSArray *statusLabels; 24 | 25 | @end 26 | 27 | @implementation AppDelegate 28 | 29 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 30 | { 31 | self.statusLabels = @[self.calendarLabel, self.remindersLabel, self.contactsLabel, self.photosLabel, self.fullDiskAccessLabel]; 32 | [self _updateLabels]; 33 | } 34 | 35 | #pragma mark - Actions 36 | 37 | - (IBAction)authorize:(NSButton *)button 38 | { 39 | [MPPermissionsKit requestAuthorizationForPermissionType:button.tag withCompletion:^(MPAuthorizationStatus status) { 40 | dispatch_async(dispatch_get_main_queue(), ^{ 41 | self.statusLabels[button.tag].stringValue = [self _stringFromStatus:status]; 42 | }); 43 | }]; 44 | } 45 | 46 | #pragma mark - Private 47 | 48 | - (void)_updateLabels 49 | { 50 | [self.statusLabels enumerateObjectsUsingBlock:^(NSTextField * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 51 | MPAuthorizationStatus status = [MPPermissionsKit authorizationStatusForPermissionType:idx]; 52 | obj.stringValue = [self _stringFromStatus:status]; 53 | }]; 54 | } 55 | 56 | - (NSString *)_stringFromStatus:(MPAuthorizationStatus)authorizationStatus 57 | { 58 | switch (authorizationStatus) { 59 | case MPAuthorizationStatusDenied: return @"Denied"; 60 | case MPAuthorizationStatusAuthorized: return @"Authorized"; 61 | case MPAuthorizationStatusNotDetermined: return @"Not determined"; 62 | case MPAuthorizationStatusLimited: return @"Limited"; 63 | } 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /PermissionsKitTestApp/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 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 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 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 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | Default 545 | 546 | 547 | 548 | 549 | 550 | 551 | Left to Right 552 | 553 | 554 | 555 | 556 | 557 | 558 | Right to Left 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | Default 570 | 571 | 572 | 573 | 574 | 575 | 576 | Left to Right 577 | 578 | 579 | 580 | 581 | 582 | 583 | Right to Left 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | -------------------------------------------------------------------------------- /PermissionsKitTestApp/Entitlements/PermissionsKitTestApp-Sandboxed.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.temporary-exception.files.home-relative-path.read-only 8 | 9 | Library/Safari/Bookmarks.plist 10 | Library/Safari/CloudTabs.db 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /PermissionsKitTestApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSCalendarsUsageDescription 26 | Test Description Calendars 27 | NSContactsUsageDescription 28 | Test Description Contacts 29 | NSHumanReadableCopyright 30 | Copyright © 2018 MacPaw. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPhotoLibraryAddUsageDescription 34 | P 35 | NSPhotoLibraryUsageDescription 36 | Photos Desc 37 | NSPrincipalClass 38 | NSApplication 39 | NSRemindersUsageDescription 40 | Test Description Reminders 41 | 42 | 43 | -------------------------------------------------------------------------------- /PermissionsKitTestApp/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PermissionsKitTestApp 4 | // 5 | // Created by Sergii Kryvoblotskyi on 9/12/18. 6 | // Copyright © 2018 MacPaw. All rights reserved. 7 | // 8 | 9 | @import Cocoa; 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PermissionsKit 2 | 3 | 4 | [![CI Status](https://img.shields.io/travis/MacPaw/PermissionsKit.svg?style=flat)](https://travis-ci.org/MacPaw/PermissionsKit) 5 | [![Version](https://img.shields.io/cocoapods/v/PermissionsKit-macOS.svg?style=flat)](https://cocoapods.org/pods/PermissionsKit-macOS) 6 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-FC6956.svg?style=flat)](https://github.com/MacPaw/PermissionsKit) 7 | [![Platform](https://img.shields.io/cocoapods/p/PermissionsKit-macOS.svg?style=flat)](https://cocoapods.org/pods/PermissionsKit-macOS) 8 | [![License](https://img.shields.io/cocoapods/l/PermissionsKit-macOS.svg?style=flat)](https://cocoapods.org/pods/PermissionsKit-macOS) 9 | 10 | ![Calendar](https://github.com/MacPaw/PermissionsKit/raw/master/Screenshots/logo.png) 11 | 12 | The convenient wrapper on macOS permissions API. 13 | 14 | Current implementation supports permissions for: 15 | 16 | * [Calendar](#calendar) 17 | * [Contacts](#contacts) 18 | * [Reminders](#reminders) 19 | * [Photos](#photos) 20 | * [Full Disk Access](#full-disk-access) 21 | 22 | ## Usage 23 | 24 | Available types: 25 | ```objc 26 | typedef NS_ENUM(NSUInteger, MPPermissionType) { 27 | MPPermissionTypeCalendar = 0, 28 | MPPermissionTypeReminders, 29 | MPPermissionTypeContacts, 30 | MPPermissionTypePhotos, 31 | MPPermissionTypeFullDiskAccess 32 | } NS_SWIFT_NAME(PermissionType); 33 | ``` 34 | 35 | Get permissions status: 36 | ```objc 37 | /** 38 | * Requests current authorization status for a given type. 39 | * 40 | * @discussion It is safe to call this method on system where permission type is not supported. MPAuthorizationStatusAuthorized will be returned. 41 | * 42 | * @param permissionType MPPermissionType 43 | * @return MPAuthorizationStatus 44 | */ 45 | + (MPAuthorizationStatus)authorizationStatusForPermissionType:(MPPermissionType)permissionType; 46 | ``` 47 | 48 | Ask for permissions: 49 | ```objc 50 | /** 51 | * Requests user authorization for a given permission. Completion will be invoked with a user decision. Completion queue is undefined. 52 | * @discussion There will be no completion when requesting MPPermissionTypeFullDiskAccess, because its status is unknown. You should implement your own callback mechanism, for example - polling authorization. It is safe to call this method on system where permission type is not supported. MPAuthorizationStatusAuthorized will be returned. 53 | * 54 | * @param permissionType MPPermissionType 55 | * @param completionHandler void (^)(MPAuthorizationStatus status) 56 | */ 57 | + (void)requestAuthorizationForPermissionType:(MPPermissionType)permissionType withCompletion:(void (^)(MPAuthorizationStatus status))completionHandler; 58 | ``` 59 | 60 | ## Calendar 61 | 10.9+ 62 | 63 | ![Calendar](https://github.com/MacPaw/PermissionsKit/raw/master/Screenshots/calendar.png) 64 | 65 | `NSCalendarsUsageDescription` key in info.plist is required. 66 | 67 | ## Contacts 68 | 10.11+ 69 | 70 | ![Contacts](https://github.com/MacPaw/PermissionsKit/raw/master/Screenshots/contacts.png) 71 | 72 | :warning:Uses **Private API** for calling permissions, because public one is not working properly. See [rdar://34158737](http://www.openradar.me/34158737) 73 | 74 | `NSContactsUsageDescription` key is required in Info.plist 75 | 76 | ## Reminders 77 | 10.9+ 78 | 79 | ![Reminders](https://github.com/MacPaw/PermissionsKit/raw/master/Screenshots/reminders.png) 80 | 81 | `NSRemindersUsageDescription` key is required in Info.plist 82 | 83 | ## Photos 84 | 10.13+ 85 | 86 | :warning:Works only for Photos Extensions. See [rdar://34431396](http://www.openradar.me/34431396) and [rdar://43426722](http://www.openradar.me/43426722) 87 | 88 | `NSPhotoLibraryUsageDescription` key is required in Info.plist 89 | 90 | ## Full Disk Access 91 | 10.14+ 92 | 93 | ![FDA](https://github.com/MacPaw/PermissionsKit/raw/master/Screenshots/full_disk_access.png) 94 | 95 | Since there is no legal API to request Full Disk Access permissions on macOS 10.14, this is the only workaround to get and ask for it. 96 | 97 | :warning:There will be no callback when requesting this type of permission, so you should use your own implementation such as polling permission status, or use other events to handle possible permission change (for example handle `NSApp` foreground/background status). 98 | Calling for permissions opens Preferences->Privacy with selected "Full Disk Access" section. 99 | 100 | ## Application Sandbox: 101 | 102 | PermissionsKit can be used in sandboxed applications. It uses multiple files to check for FDA status in case some of the 103 | tested files are unaccessible due to reasons unrelated to FDA (not present on older systems, UNIX permissions, etc.) 104 | The files are: 105 | * `~/Library/Safari/Bookmarks.plist` 106 | * `~/Library/Safari/CloudTabs.db` 107 | * `/Library/Application Support/com.apple.TCC/TCC.db` 108 | * `/Library/Preferences/com.apple.TimeMachine.plist` 109 | Your app needs to be able to access those files under sandbox. You can do it using Security-Scoped Bookmarks flow(e.g. having a bookmark for root folder), more details in [apple documentation](https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) 110 | Or for testing purposes you can add temporary-exception to your .entitlements file. 111 | 112 | ``` 113 | com.apple.security.temporary-exception.files.home-relative-path.read-only 114 | 115 | Library/Safari/Bookmarks.plist 116 | Library/Safari/CloudTabs.db 117 | 118 | com.apple.security.temporary-exception.files.absolute-path.read-only 119 | 120 | /Library/Application Support/com.apple.TCC/TCC.db 121 | /Library/Preferences/com.apple.TimeMachine.plist 122 | 123 | ``` 124 | 125 | For more details please check [Full Disk Access](#full-disk-access) details. 126 | 127 | 128 | ## Installation 129 | 130 | ### CocoaPods 131 | PermissionsKit is available through [CocoaPods](https://cocoapods.org). To install it, simply add the following line to your Podfile: 132 | ```ruby 133 | pod 'PermissionsKit-macOS' 134 | ``` 135 | 136 | ### Carthage 137 | PermissionsKit is available through [Carthage](https://github.com/Carthage/Carthage). To install it, simple add the following line to your Cartfile: 138 | ```ruby 139 | github "MacPaw/PermissionsKit" 140 | ``` 141 | 142 | ### Manual 143 | For manual installation just choose the latest available [Release](https://github.com/MacPaw/PermissionsKit/releases) and drag and drop the framework to you project. (You may also need to add it to Embedded Binaries). 144 | 145 | ## Requirements 146 | 147 | macOS 10.9+ 148 | However different kinds of permissions require different system version it is safe to call for authorization witout actual system check. `MPAuthorizationStatusAuthorized` will be returned in this case. 149 | 150 | ## Example 151 | 152 | See PermissionsKitTestApp target 153 | 154 | ![TestAppScreenshot](https://github.com/MacPaw/PermissionsKit/raw/master/Screenshots/test_app.png) 155 | 156 | ## Useful links 157 | 158 | * [Full Disk Access](https://forums.developer.apple.com/thread/107546) 159 | * [Contacts](https://developer.apple.com/documentation/contacts/cncontactstore/1402873-requestaccessforentitytype?language=objc) 160 | * [Calendar, Reminders](https://developer.apple.com/documentation/eventkit/ekeventstore/1507239-authorizationstatusforentitytype) 161 | * [Photos](https://developer.apple.com/documentation/photokit/phphotolibrary/1620736-requestauthorization?language=objc) 162 | * [tccutil](https://bitsplitting.org/2018/07/11/reauthorizing-automation-in-mojave/) 163 | 164 | ## License 165 | 166 | MIT License 167 | 168 | Copyright (c) 2018 MacPaw 169 | 170 | Permission is hereby granted, free of charge, to any person obtaining a copy 171 | of this software and associated documentation files (the "Software"), to deal 172 | in the Software without restriction, including without limitation the rights 173 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 174 | copies of the Software, and to permit persons to whom the Software is 175 | furnished to do so, subject to the following conditions: 176 | 177 | The above copyright notice and this permission notice shall be included in all 178 | copies or substantial portions of the Software. 179 | 180 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 181 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 182 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 183 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 184 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 185 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 186 | SOFTWARE. 187 | -------------------------------------------------------------------------------- /Screenshots/calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacPaw/PermissionsKit/97c2636fabe4e6cf617033dea3f8a1ac303060cd/Screenshots/calendar.png -------------------------------------------------------------------------------- /Screenshots/contacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacPaw/PermissionsKit/97c2636fabe4e6cf617033dea3f8a1ac303060cd/Screenshots/contacts.png -------------------------------------------------------------------------------- /Screenshots/full_disk_access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacPaw/PermissionsKit/97c2636fabe4e6cf617033dea3f8a1ac303060cd/Screenshots/full_disk_access.png -------------------------------------------------------------------------------- /Screenshots/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacPaw/PermissionsKit/97c2636fabe4e6cf617033dea3f8a1ac303060cd/Screenshots/logo.png -------------------------------------------------------------------------------- /Screenshots/reminders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacPaw/PermissionsKit/97c2636fabe4e6cf617033dea3f8a1ac303060cd/Screenshots/reminders.png -------------------------------------------------------------------------------- /Screenshots/test_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacPaw/PermissionsKit/97c2636fabe4e6cf617033dea3f8a1ac303060cd/Screenshots/test_app.png -------------------------------------------------------------------------------- /Scripts/buildAndZipAll.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | function help() { 4 | echo "Usage: $(basename "$0") [-quiet]" 5 | echo "Options:" 6 | echo " -quiet: building scheme in quiet mode" 7 | echo " -h, --help: display this help" 8 | echo "Examples:" 9 | echo " $(basename "$0") -quiet" 10 | exit 0 11 | } 12 | 13 | SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 14 | PROJ_DIR="$(dirname "$SCRIPT_DIR")" 15 | ARTIFACTS_DIR="$PROJ_DIR/artifacts" 16 | 17 | QUIET="" 18 | 19 | while [ $# -gt 0 ] 20 | do 21 | case "$1" in 22 | -quiet) 23 | QUIET="-quiet" 24 | shift 25 | ;; 26 | -h|--help) 27 | help 28 | ;; 29 | *) 30 | echo "Unknown input parameter \"$1\". Run with --help or -h for help." 31 | exit 1 32 | ;; 33 | esac 34 | done 35 | 36 | check_utility_result() 37 | { 38 | RESULT="$1" 39 | if [ $RESULT != 0 ]; then 40 | exit $RESULT 41 | fi 42 | } 43 | 44 | add_artifact() 45 | { 46 | ARTIFACT="$1" 47 | mkdir -p "$ARTIFACTS_DIR" 48 | mv "$ARTIFACT" "$ARTIFACTS_DIR" 49 | } 50 | 51 | buildAndArchive() 52 | { 53 | echo "------------ BUILD ------------" 54 | PROJECT="$PROJ_DIR/PermissionsKit.xcodeproj" 55 | SCHEME="PermissionsKit" 56 | BUILD_CONFIG="Release" 57 | DEBUG_INFORMATION_FORMAT="dwarf-with-dsym" 58 | SKIP_OBFUSCATION="NO" 59 | 60 | if [ ! -z "$QUIET" ]; then 61 | echo "Building scheme in quiet mode..." 62 | echo "\tCONFIGURATION = $BUILD_CONFIG" 63 | echo "\tDEBUG_INsFORMATION_FORMAT = $DEBUG_INFORMATION_FORMAT" 64 | echo "\tSKIP_OBFUSCATION = $SKIP_OBFUSCATION" 65 | fi 66 | 67 | xcodebuild clean build \ 68 | $QUIET \ 69 | -project "$PROJECT" \ 70 | -scheme "$SCHEME" \ 71 | -configuration "$BUILD_CONFIG" \ 72 | DEBUG_INFORMATION_FORMAT="$DEBUG_INFORMATION_FORMAT" \ 73 | SKIP_OBFUSCATION=$SKIP_OBFUSCATION 74 | check_utility_result $? 75 | 76 | PRODUCTS_DIR=$(xcodebuild -project "$PROJECT" \ 77 | -scheme "$SCHEME" \ 78 | -configuration "$BUILD_CONFIG" \ 79 | -showBuildSettings \ 80 | | grep "BUILT_PRODUCTS_DIR" \ 81 | | grep -oEi "\/.*") 82 | 83 | echo "PRODUCTS_DIR = $PRODUCTS_DIR" 84 | cd "$PRODUCTS_DIR" 85 | 86 | ARTIFACTS=("PermissionsKit.framework" \ 87 | "PermissionsKit.framework.dSYM") 88 | for ARTIFACT in "${ARTIFACTS[@]}" 89 | do 90 | if [ -e "$ARTIFACT" ]; then 91 | zip -r -y "$ARTIFACT.zip" "$ARTIFACT"; check_utility_result $? 92 | add_artifact "$ARTIFACT.zip"; check_utility_result $? 93 | fi 94 | done 95 | } 96 | 97 | rm -rf "$ARTIFACTS_DIR" 98 | buildAndArchive 99 | 100 | echo "Finished successfuly" 101 | exit 0 102 | --------------------------------------------------------------------------------