Skip to content

Commit

Permalink
support swiftpackage
Browse files Browse the repository at this point in the history
  • Loading branch information
DevLiuSir committed Jan 17, 2024
1 parent ee664bc commit 5e86423
Show file tree
Hide file tree
Showing 11 changed files with 507 additions and 0 deletions.
28 changes: 28 additions & 0 deletions Package.swift
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"]),
]
)
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)
}
}
}
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)
}
}
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)
}
}

}
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)
}
}
}
24 changes: 24 additions & 0 deletions Sources/LCPermissionsKit/Private/LCAuthorizer.swift
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)
}

Loading

0 comments on commit 5e86423

Please sign in to comment.