惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
C
CERT Recently Published Vulnerability Notes
雷峰网
雷峰网
美团技术团队
L
LangChain Blog
Google DeepMind News
Google DeepMind News
博客园 - 【当耐特】
I
InfoQ
www.infosecurity-magazine.com
www.infosecurity-magazine.com
J
Java Code Geeks
B
Blog
博客园 - 三生石上(FineUI控件)
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Secure Thoughts
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园_首页
博客园 - Franky
Apple Machine Learning Research
Apple Machine Learning Research
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
GbyAI
GbyAI
TaoSecurity Blog
TaoSecurity Blog
N
Netflix TechBlog - Medium
H
Heimdal Security Blog
T
Troy Hunt's Blog
N
News and Events Feed by Topic
V2EX - 技术
V2EX - 技术
腾讯CDC
Forbes - Security
Forbes - Security
P
Privacy & Cybersecurity Law Blog
I
Intezer
Hacker News - Newest:
Hacker News - Newest: "LLM"
Y
Y Combinator Blog
The Register - Security
The Register - Security
Martin Fowler
Martin Fowler
Hugging Face - Blog
Hugging Face - Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
L
Lohrmann on Cybersecurity
Security Latest
Security Latest
AWS News Blog
AWS News Blog
Scott Helme
Scott Helme
Webroot Blog
Webroot Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MongoDB | Blog
MongoDB | Blog
Vercel News
Vercel News
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
S
Security Affairs
P
Privacy International News Feed

壹拾肆

2024 年做过的一些梦 2023 年做过的一些梦 2023 年终总结丨随时开始奔跑的心气 2022 年终总结丨惠存这一年 翻译:Why use dependency injection 是时候维护一个属于自己的开源库了 iOS 端豆瓣开源许可提到的库 推荐几个播客节目 iOS 自动化打包上传 AppleStore、fir.im,并发邮件通知测试人员 业余剪辑自我修养 iOS - HMAC 加密算法和一个 MD5 加密的问题 iOS - 一些蓝牙问题的解决 Swift - 顶部弹出框封装 被光放弃的人 OC - 多代理的实现 我的 AIO-notion 工作流搭建 解决使用 GitPage 重定向多次问题 Swift - ?和!的学习 《文学回忆录》读书笔记
Swift - 权限请求封装
Kaaaaai · 2020-09-12 · via 壹拾肆

注意到工程里面关于权限请求这块的逻辑没有很好地管理起来,一些是用 OC 的工具类,一些是用 Swift 代码在一些 ViewController 里面单独调用,不能复用,就想封装一个 Swift 版关于权限请求的工具类,虽然这个需求在 GitHub 上搜索也有很多现成的轮子,但使用起来感觉太重,而且有些久不维护,Swift 版本更新的又快,有些接口就不好使了,索性就自己封装一个。

一开始的思路也是想通过枚举来创建不同权限字段,通过静态方法来实现请求,但是蓝牙权限和定位权限需要实例化对象,设置代理。当使用 static 关键字来创建蓝牙和定位对象,当应用内有其他的业务也要使用蓝牙和定位对象时,代理响应就会有点问题。后面索性就用单例方法创建一个整体的权限管理对象,然后创建类方法,在类方法中自己调用自己。

过程中也参考了以下开源仓库的一些逻辑:

当前封装的库仍存在的一个问题是,暂时未做到对所有权限的海陆空全方位覆盖,只是针对当前我们应用业务所使用到的权限的封装。

好了,话不多说上代码:

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

public enum PermissionStatus: String {
case authorized = "Authorized"
case denied = "Denied"
case disabled = "Disabled"
case notDetermined = "Not Determined"

init?(string: String?) {
guard let string = string else { return nil }
self.init(rawValue: string)
}
}

extension PermissionStatus: CustomStringConvertible {

public var description: String {
return rawValue
}
}

extension KKPermissions {
public typealias Callback = (PermissionStatus) -> Void
}


extension KKPermissions{

public static func requestBluetooth(_ callback: @escaping Callback){
KKPermissions.provide.bluetoothManager = KKPermissions.provide.createBluetoothManager()

KKPermissions.provide.bluetoothCallBack = callback
KKPermissions.provide.bluetoothManager.startAdvertising(nil)
KKPermissions.provide.bluetoothManager.stopAdvertising()
}


public static func requestLocationWhenInUse(_ callback: @escaping Callback){
KKPermissions.provide.LocationManager = KKPermissions.provide.createLocationManager()
KKPermissions.provide.locationCallBack = callback
KKPermissions.provide.LocationManager.requestWhenInUseAuthorization()
}


public static func requestLocationAlways(_ callback: @escaping Callback){
KKPermissions.provide.LocationManager = KKPermissions.provide.createLocationManager()
KKPermissions.provide.locationCallBack = callback
KKPermissions.provide.LocationManager.requestAlwaysAuthorization()
}


public static func requestMicrophone(_ callback: @escaping Callback){
let audioSession = AVAudioSession.sharedInstance()
audioSession.requestRecordPermission { (allowed) in
if allowed {
callback(.authorized)
}else{
callback(.denied)
}
}
}


public static func requestContacts(_ callback: @escaping Callback) {


let status = CNContactStore.authorizationStatus(for: .contacts)

var phoneStatus: PermissionStatus


if status == .notDetermined {


let store = CNContactStore()

phoneStatus = .notDetermined

store.requestAccess(for: .contacts, completionHandler: {(isRight : Bool,error : Error?) in

if isRight {
print("授权成功")
phoneStatus = .authorized
} else {
phoneStatus = .denied
print("授权失败")
}

callback(phoneStatus)
})
}else if status != .authorized {
phoneStatus = .denied
callback(phoneStatus)
}else{
phoneStatus = .authorized
callback(phoneStatus)
}
}


static func requestPhoto(_ callback: @escaping Callback) {
let granted = PHPhotoLibrary.authorizationStatus()
switch granted {
case PHAuthorizationStatus.authorized:
callback(.authorized)
case PHAuthorizationStatus.denied, PHAuthorizationStatus.restricted:
callback(.denied)
case PHAuthorizationStatus.notDetermined:
PHPhotoLibrary.requestAuthorization({ status in
DispatchQueue.main.async {
if status == .authorized{
callback(.authorized)
}else{
callback(.denied)
}
}
})
@unknown default:
callback(.denied)
}
}


static func requestCamera(_ callback: @escaping Callback) {
let granted = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
switch granted {
case .authorized:
callback(.authorized)
case .denied,.restricted:
callback(.denied)
case .notDetermined:
AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { (granted: Bool) in
DispatchQueue.main.async {
if granted {
callback(.authorized)
}else{
callback(.denied)
}
}
})
@unknown default:
callback(.denied)
}
}


public static func jumpToSystemPrivacySetting() {
guard let appSetting = URL(string: UIApplication.openSettingsURLString) else {
return
}
if #available(iOS 10, *) {
UIApplication.shared.open(appSetting, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(appSetting)
}
}
}

class KKPermissions: NSObject {

private func createBluetoothManager() -> CBPeripheralManager{
let bluetoothManager = CBPeripheralManager(
delegate: KKPermissions.provide,
queue: nil,
options: nil)
return bluetoothManager
}

private func createLocationManager() -> CLLocationManager{
let locManager = CLLocationManager()
locManager.delegate = KKPermissions.provide
return locManager
}

private var LocationManager:CLLocationManager!

private static var locationState: PermissionStatus?

private var locationCallBack: Callback?

private var bluetoothManager: CBPeripheralManager!

private var bluetoothCallBack: Callback?

private static var bluetoothState: PermissionStatus?

private static let provide:KKPermissions = KKPermissions()

private override init() {
super.init()
}
}


extension KKPermissions: CLLocationManagerDelegate,CBPeripheralManagerDelegate{
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

guard KKPermissions.provide.LocationManager != nil else {
return
}

switch status {
case .authorizedAlways, .authorizedWhenInUse:
KKPermissions.locationState = .authorized
break
case .restricted, .denied:
KKPermissions.locationState = .denied
break
case .notDetermined:
KKPermissions.locationState = .notDetermined
break
@unknown default:
KKPermissions.locationState = .notDetermined
break
}

self.locationCallBack?(KKPermissions.locationState!)

self.locationCallBack = nil
}

func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
print(">>>>>权限状态测试 KKpermissions \(peripheral.state)")

guard KKPermissions.provide.bluetoothManager != nil else {
return
}

switch peripheral.state {
case .unsupported, .poweredOff:
KKPermissions.bluetoothState = .disabled
break
case .unauthorized:
KKPermissions.bluetoothState = .denied
break
case .poweredOn:
KKPermissions.bluetoothState = .authorized
break
case .resetting, .unknown:
KKPermissions.bluetoothState = .notDetermined
break
@unknown default:
KKPermissions.bluetoothState = .notDetermined
break
}

self.bluetoothCallBack?(KKPermissions.bluetoothState!)


self.bluetoothCallBack = nil
}
}

附上一个简单的 UI 效果: