-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
507 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// swift-tools-version: 5.7 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "LCPermissionsKit", | ||
products: [ | ||
// Products define the executables and libraries a package produces, and make them visible to other packages. | ||
.library( | ||
name: "LCPermissionsKit", | ||
targets: ["LCPermissionsKit"]), | ||
], | ||
dependencies: [ | ||
// Dependencies declare other packages that this package depends on. | ||
// .package(url: /* package url */, from: "1.0.0"), | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package. A target can define a module or a test suite. | ||
// Targets can depend on other targets in this package, and on products in packages this package depends on. | ||
.target( | ||
name: "LCPermissionsKit", | ||
dependencies: []), | ||
.testTarget( | ||
name: "LCPermissionsKitTests", | ||
dependencies: ["LCPermissionsKit"]), | ||
] | ||
) |
70 changes: 70 additions & 0 deletions
70
Sources/LCPermissionsKit/Private/Calendar/LCCalendarAuthorizer.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// | ||
// LCCalendarAuthorizer.swift | ||
// LCPermissionsKit | ||
// | ||
// Created by Liu Chuan on 2023/1/17. | ||
// | ||
|
||
import Cocoa | ||
import EventKit | ||
|
||
/// 日历权限 授权器 | ||
class LCCalendarAuthorizer: NSObject { | ||
|
||
// 事件实体类型,默认为事件 | ||
private var entityType: EKEntityType | ||
|
||
/// 创建事件权限授权器实例 | ||
static func events() -> LCCalendarAuthorizer { | ||
return LCCalendarAuthorizer(entityType: .event) | ||
} | ||
|
||
/// 创建提醒事项权限授权器实例 | ||
static func reminders() -> LCCalendarAuthorizer { | ||
return LCCalendarAuthorizer(entityType: .reminder) | ||
} | ||
|
||
/// 初始化方法,设置实体类型 | ||
/// | ||
/// - Parameter entityType: 要授权的日历实体类型 | ||
init(entityType: EKEntityType) { | ||
self.entityType = entityType | ||
} | ||
|
||
/// 将`事件权限授权状态`转换为`自定义权限授权状态` | ||
/// | ||
/// - Parameter status: EKAuthorizationStatus,事件权限的授权状态 | ||
/// - Returns: LCAuthorizationStatus,对应的自定义权限授权状态 | ||
private func authorizationStatus(from status: EKAuthorizationStatus) -> LCAuthorizationStatus { | ||
switch status { | ||
case .denied, .restricted: | ||
return .denied | ||
case .authorized: | ||
return .authorized | ||
case .notDetermined: | ||
return .notDetermined | ||
@unknown default: | ||
return .notDetermined | ||
} | ||
} | ||
} | ||
|
||
//MARK: - LCAuthorizer | ||
extension LCCalendarAuthorizer: LCAuthorizer { | ||
|
||
func authorizationStatus() -> LCAuthorizationStatus { | ||
// 获取事件(日历)权限的授权状态 | ||
let status = EKEventStore.authorizationStatus(for: self.entityType) | ||
return authorizationStatus(from: status) | ||
|
||
} | ||
// 请求事件(日历)权限的授权 | ||
func requestAuthorization(withCompletion completionHandler: @escaping (LCAuthorizationStatus) -> Void) { | ||
// 创建事件(日历)存储对象 | ||
let store = EKEventStore() | ||
// 请求事件(日历)权限 | ||
store.requestAccess(to: self.entityType) { (granted, error) in | ||
completionHandler(granted ? .authorized : .denied) | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
Sources/LCPermissionsKit/Private/Contacts/LCContactsAuthorization.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// LCContactsAuthorization.swift | ||
// LCPermissionsKit | ||
// | ||
// Created by Liu Chuan on 2023/1/17. | ||
// | ||
|
||
import Foundation | ||
import Contacts | ||
|
||
/// 联系人授权 | ||
class LCContactsAuthorization: NSObject { | ||
|
||
/// 获取通讯录实体类型的授权状态 | ||
/// | ||
/// - Parameter entityType: 要查询的通讯录实体类型 | ||
/// - Returns: 授权状态 | ||
static func authorizationStatus(for entityType: CNEntityType) -> CNAuthorizationStatus { | ||
return CNContactStore.authorizationStatus(for: entityType) | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
Sources/LCPermissionsKit/Private/Contacts/LCContactsAuthorizer.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// | ||
// LCContactsAuthorizer.swift | ||
// LCPermissionsKit | ||
// | ||
// Created by Liu Chuan on 2023/1/17. | ||
// | ||
|
||
import Cocoa | ||
import Contacts | ||
|
||
/// 联系人授权器 | ||
class LCContactsAuthorizer: NSObject { | ||
|
||
/// 将 `CNAuthorizationStatus` 转换为 `LCAuthorizationStatus` | ||
/// | ||
/// - Parameter status: CNAuthorizationStatus,通讯录权限的授权状态 | ||
/// - Returns: LCAuthorizationStatus,对应的自定义权限授权状态 | ||
private func authorizationStatus(from status: CNAuthorizationStatus) -> LCAuthorizationStatus { | ||
/// 根据通讯录权限状态进行判断并转换 | ||
switch status { | ||
case .denied, .restricted: | ||
return .denied | ||
case .authorized: | ||
return .authorized | ||
case .notDetermined: | ||
return .notDetermined | ||
@unknown default: | ||
return .notDetermined | ||
} | ||
} | ||
} | ||
|
||
//MARK: - LCAuthorizer | ||
extension LCContactsAuthorizer: LCAuthorizer { | ||
|
||
func authorizationStatus() -> LCAuthorizationStatus { | ||
if #available(macOS 10.11, *) { | ||
// 获取系统通讯录权限状态 | ||
let authorizationStatus = CNContactStore.authorizationStatus(for: .contacts) | ||
return self.authorizationStatus(from: authorizationStatus) | ||
} else { // 在 macOS 10.11 以下版本,默认返回已授权 | ||
return .authorized | ||
} | ||
} | ||
|
||
func requestAuthorization(withCompletion completionHandler: @escaping (LCAuthorizationStatus) -> Void) { | ||
if #available(macOS 10.11, *) { // 在 macOS 10.11 及以上版本,使用 CNContactStore 请求通讯录权限 | ||
let store = CNContactStore() | ||
store.requestAccess(for: .contacts) { (granted, error) in | ||
completionHandler(granted ? .authorized : .denied) | ||
} | ||
} else { // 在 macOS 10.11 以下版本,默认返回已授权 | ||
completionHandler(.authorized) | ||
} | ||
} | ||
|
||
} |
144 changes: 144 additions & 0 deletions
144
Sources/LCPermissionsKit/Private/FullDiskAccess/LCFullDiskAccessAuthorizer.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// | ||
// LCFullDiskAccessAuthorizer.swift | ||
// LCPermissionsKit | ||
// | ||
// Created by Liu Chuan on 2023/1/17. | ||
// | ||
|
||
import Cocoa | ||
|
||
|
||
|
||
class LCFullDiskAccessAuthorizer: NSObject { | ||
|
||
/// 共享的单例实例 | ||
static let shared = LCFullDiskAccessAuthorizer() | ||
|
||
/// 文件管理器 | ||
private var fileManager: FileManager | ||
|
||
/// 工作区 | ||
private var workspace: NSWorkspace | ||
|
||
/// 用户主目录路径 | ||
private var userHomeFolderPath: String? | ||
|
||
// 初始化方法,可以传入`自定义的文件管理器`和`工作区` | ||
init(fileManager: FileManager = FileManager.default, workspace: NSWorkspace = NSWorkspace.shared) { | ||
self.fileManager = fileManager | ||
self.workspace = workspace | ||
} | ||
|
||
/// 检查`完全磁盘访问权限`,使用`指定文件`进行检测 | ||
/// | ||
/// - Parameter path: 指定的文件路径 | ||
/// - Returns: LCAuthorizationStatus,完全磁盘访问权限的授权状态 | ||
private func checkFDA(usingFile path: String) -> LCAuthorizationStatus { | ||
// 尝试以 只读模式 打开 指定路径 的文件 | ||
let file = open(path, O_RDONLY) | ||
|
||
// 检查文件是否成功打开 | ||
if file != -1 { | ||
// 如果成功打开,则 关闭文件 并返回 已授权 状态 | ||
close(file) | ||
return .authorized | ||
} | ||
|
||
// 如果打开文件失败,则检查错误码以确定授权状态 | ||
if errno == EPERM || errno == EACCES { | ||
// 如果权限不足,则返回拒绝状态 | ||
return .denied | ||
} | ||
|
||
// 如果未确定授权状态,则返回未确定状态 | ||
return .notDetermined | ||
} | ||
|
||
/// 获取`完全磁盘访问权限`的`授权状态` | ||
/// | ||
/// - Returns: LCAuthorizationStatus,完全磁盘访问权限的授权状态 | ||
private func fullDiskAuthorizationStatus() -> LCAuthorizationStatus { | ||
// 定义测试文件路径数组 | ||
let testFiles = [ | ||
getUserHomeFolderPath().appending("/Library/Safari/CloudTabs.db"), | ||
getUserHomeFolderPath().appending("/Library/Safari/Bookmarks.plist"), | ||
"/Library/Application Support/com.apple.TCC/TCC.db", | ||
"/Library/Preferences/com.apple.TimeMachine.plist", | ||
] | ||
|
||
// 初始化授权状态为未确定 | ||
var resultStatus = LCAuthorizationStatus.notDetermined | ||
|
||
// 遍历 测试文件路径 数组,检查每个文件的 磁盘访问权限 | ||
for file in testFiles { | ||
let status = checkFDA(usingFile: file) | ||
|
||
// 如果有一个文件已授权,则整体状态为已授权,并跳出循环 | ||
if status == .authorized { | ||
resultStatus = .authorized | ||
break | ||
} | ||
|
||
// 如果有一个文件权限被拒绝,则整体状态为被拒绝 | ||
if status == .denied { | ||
resultStatus = .denied | ||
} | ||
} | ||
|
||
// 返回最终的磁盘访问权限授权状态 | ||
return resultStatus | ||
} | ||
|
||
|
||
/// 获取用户主目录路径 | ||
/// | ||
/// - Returns: 用户主目录路径 | ||
private func getUserHomeFolderPath() -> String { | ||
if let path = userHomeFolderPath { | ||
return path | ||
} | ||
let isSandboxed = ProcessInfo.processInfo.environment["APP_SANDBOX_CONTAINER_ID"] != nil | ||
if isSandboxed { // 沙盒 | ||
let pw = getpwuid(getuid()) | ||
assert(pw != nil) | ||
userHomeFolderPath = String(cString: pw!.pointee.pw_dir) | ||
} else { // 非沙盒 | ||
userHomeFolderPath = NSHomeDirectory() | ||
} | ||
return userHomeFolderPath! | ||
} | ||
|
||
/// 打开系统偏好设置 - 完全磁盘访问权限 | ||
private func openPreferences() { | ||
// 使用工作区打开系统偏好设置中的完全磁盘访问权限设置页面 | ||
workspace.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles")!) | ||
} | ||
} | ||
|
||
|
||
|
||
//MARK: - LCAuthorizer | ||
extension LCFullDiskAccessAuthorizer: LCAuthorizer { | ||
|
||
func authorizationStatus() -> LCAuthorizationStatus { | ||
//MARK: 获取 完全磁盘访问权限 的 授权状态 | ||
if #available(macOS 10.14, *) { | ||
// 获取系统完全磁盘访问权限状态 | ||
return fullDiskAuthorizationStatus() | ||
} else { | ||
// 在 macOS 10.14 以下版本,默认返回已授权 | ||
return .authorized | ||
} | ||
} | ||
|
||
func requestAuthorization(withCompletion completionHandler: @escaping (LCAuthorizationStatus) -> Void) { | ||
//MARK: 请求完全磁盘访问权限的授权 | ||
if #available(macOS 10.14, *) { | ||
// 在 macOS 10.14 及以上版本,打开系统偏好设置页面 | ||
openPreferences() | ||
} else { | ||
// 在 macOS 10.14 以下版本,默认返回已授权 | ||
completionHandler(.authorized) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// | ||
// LCAuthorizer.swift | ||
// LCPermissionsKit | ||
// | ||
// Created by Liu Chuan on 2023/1/17. | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
/// 权限授权器的协议 | ||
protocol LCAuthorizer { | ||
|
||
/// 获取`权限`的`授权状态` | ||
/// | ||
/// - Returns: LCAuthorizationStatus,权限的授权状态 | ||
func authorizationStatus() -> LCAuthorizationStatus | ||
|
||
/// `请求权限`的`授权` | ||
/// | ||
/// - Parameter completionHandler: 授权请求完成后的回调,返回授权状态 | ||
func requestAuthorization(withCompletion completionHandler: @escaping (LCAuthorizationStatus) -> Void) | ||
} | ||
|
Oops, something went wrong.