expo-gaode-map-navigation 2.0.10 → 2.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -2
- package/android/build.gradle +4 -0
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNaviView.kt +501 -27
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNaviViewModule.kt +35 -0
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNavigationModule.kt +10 -23
- package/android/src/main/java/expo/modules/gaodemap/navigation/listeners/IndependentRouteListener.kt +24 -0
- package/android/src/main/java/expo/modules/gaodemap/navigation/managers/IndependentRouteManager.kt +24 -7
- package/android/src/main/java/expo/modules/gaodemap/navigation/routes/drive/DriveTruckRouteCalculator.kt +22 -35
- package/android/src/main/java/expo/modules/gaodemap/navigation/services/IndependentRouteService.kt +45 -35
- package/android/src/main/java/expo/modules/gaodemap/navigation/services/NavigationForegroundService.kt +661 -0
- package/android/src/main/java/expo/modules/gaodemap/navigation/utils/Converters.kt +2 -2
- package/android/src/main/res/drawable/ic_nav_notification_small.xml +10 -0
- package/android/src/main/res/drawable/nav_notification_brand_icon.xml +16 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_center.xml +4 -4
- package/android/src/main/res/drawable/navi_lane_shape_bg_left.xml +7 -7
- package/android/src/main/res/drawable/navi_lane_shape_bg_over.xml +5 -5
- package/android/src/main/res/drawable/navi_lane_shape_bg_right.xml +7 -7
- package/android/src/main/res/drawable-nodpi/nav_tracker_car.png +0 -0
- package/build/ExpoGaodeMapNaviView.d.ts +9 -1
- package/build/ExpoGaodeMapNaviView.d.ts.map +1 -1
- package/build/ExpoGaodeMapNaviView.js +39 -3
- package/build/ExpoGaodeMapNaviView.js.map +1 -1
- package/build/index.d.ts +32 -6
- package/build/index.d.ts.map +1 -1
- package/build/index.js +32 -6
- package/build/index.js.map +1 -1
- package/build/types/independent.types.d.ts +18 -3
- package/build/types/independent.types.d.ts.map +1 -1
- package/build/types/independent.types.js.map +1 -1
- package/build/types/naviview.types.d.ts +49 -3
- package/build/types/naviview.types.d.ts.map +1 -1
- package/build/types/naviview.types.js.map +1 -1
- package/build/types/route.types.d.ts +10 -2
- package/build/types/route.types.d.ts.map +1 -1
- package/build/types/route.types.js.map +1 -1
- package/ios/ExpoGaodeMapNaviView.swift +1526 -246
- package/ios/ExpoGaodeMapNaviViewModule.swift +22 -0
- package/ios/ExpoGaodeMapNavigationModule.swift +6 -4
- package/ios/managers/IndependentRouteManager.swift +89 -26
- package/ios/map/ExpoGaodeMapModule.swift +25 -11
- package/ios/map/modules/LocationManager.swift +10 -1
- package/ios/map/utils/PermissionManager.swift +104 -0
- package/ios/routes/drive/DriveTruckRouteCalculator.swift +157 -78
- package/ios/routes/walkride/WalkRideRouteCalculator.swift +97 -1
- package/ios/services/IndependentRouteService.swift +165 -32
- package/ios/services/NavigationLiveActivityAttributes.swift +48 -0
- package/ios/services/NavigationLiveActivityManager.swift +359 -0
- package/package.json +2 -1
- package/plugin/build/withGaodeMap.d.ts +8 -0
- package/plugin/build/withGaodeMap.js +48 -4
- package/widget-template/README.md +46 -0
- package/widget-template/ios/NavigationLiveActivityWidget.swift +367 -0
|
@@ -51,6 +51,16 @@ public class ExpoGaodeMapNaviViewModule: Module {
|
|
|
51
51
|
view.carImageSource = value
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
Prop("carImageSize") { (view: ExpoGaodeMapNaviView, value: [String: Double]?) in
|
|
55
|
+
let width = CGFloat(value?["width"] ?? 0)
|
|
56
|
+
let height = CGFloat(value?["height"] ?? 0)
|
|
57
|
+
if width > 0, height > 0 {
|
|
58
|
+
view.carImageSize = CGSize(width: width, height: height)
|
|
59
|
+
} else {
|
|
60
|
+
view.carImageSize = nil
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
54
64
|
Prop("carCompassImage") { (view: ExpoGaodeMapNaviView, value: String?) in
|
|
55
65
|
view.carCompassImageSource = value
|
|
56
66
|
}
|
|
@@ -63,6 +73,10 @@ public class ExpoGaodeMapNaviViewModule: Module {
|
|
|
63
73
|
view.wayPointImageSource = value
|
|
64
74
|
}
|
|
65
75
|
|
|
76
|
+
Prop("customWaypointMarkers") { (view: ExpoGaodeMapNaviView, value: [[String: Any]]?) in
|
|
77
|
+
view.customWaypointMarkerPayloads = value
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
Prop("endPointImage") { (view: ExpoGaodeMapNaviView, value: String?) in
|
|
67
81
|
view.endPointImageSource = value
|
|
68
82
|
}
|
|
@@ -179,6 +193,14 @@ public class ExpoGaodeMapNaviViewModule: Module {
|
|
|
179
193
|
Prop("hideNativeLaneInfoLayout") { (view: ExpoGaodeMapNaviView, value: Bool) in
|
|
180
194
|
view.hideNativeLaneInfoLayout = value
|
|
181
195
|
}
|
|
196
|
+
|
|
197
|
+
// Android-only prop, keep a no-op mapping on iOS for cross-platform prop compatibility.
|
|
198
|
+
Prop("androidBackgroundNavigationNotificationEnabled") { (_: ExpoGaodeMapNaviView, _: Bool) in
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
Prop("iosLiveActivityEnabled") { (view: ExpoGaodeMapNaviView, value: Bool) in
|
|
202
|
+
view.iosLiveActivityEnabled = value
|
|
203
|
+
}
|
|
182
204
|
|
|
183
205
|
Prop("mapViewModeType") { (view: ExpoGaodeMapNaviView, value: Int) in
|
|
184
206
|
view.mapViewModeType = value
|
|
@@ -309,8 +309,11 @@ public class ExpoGaodeMapNavigationModule: Module {
|
|
|
309
309
|
AsyncFunction("calculateMotorcycleRoute") { (options: [String: Any], promise: Promise) in
|
|
310
310
|
do {
|
|
311
311
|
try self.ensureInitialized()
|
|
312
|
-
|
|
313
|
-
|
|
312
|
+
var motorcycleOptions = options
|
|
313
|
+
if motorcycleOptions["carType"] == nil && motorcycleOptions["type"] == nil {
|
|
314
|
+
motorcycleOptions["carType"] = 11
|
|
315
|
+
}
|
|
316
|
+
self.ensureDriveTruck().calculateDriveRoute(options: motorcycleOptions, promise: promise)
|
|
314
317
|
} catch {
|
|
315
318
|
self.rejectInitializationError(promise, error: error)
|
|
316
319
|
}
|
|
@@ -321,8 +324,7 @@ public class ExpoGaodeMapNavigationModule: Module {
|
|
|
321
324
|
AsyncFunction("calculateEBikeRoute") { (options: [String: Any], promise: Promise) in
|
|
322
325
|
do {
|
|
323
326
|
try self.ensureInitialized()
|
|
324
|
-
|
|
325
|
-
self.ensureWalkRide().calculateRideRoute(options: options, promise: promise)
|
|
327
|
+
self.ensureWalkRide().calculateResolvedEleBikeRoute(options: options, promise: promise)
|
|
326
328
|
} catch {
|
|
327
329
|
self.rejectInitializationError(promise, error: error)
|
|
328
330
|
}
|
|
@@ -11,8 +11,14 @@ import AMapNaviKit
|
|
|
11
11
|
|
|
12
12
|
class IndependentRouteManager {
|
|
13
13
|
static let shared = IndependentRouteManager()
|
|
14
|
+
|
|
15
|
+
private struct Entry {
|
|
16
|
+
let scene: String
|
|
17
|
+
let routeGroup: AMapNaviRouteGroup?
|
|
18
|
+
let routeIds: [Int]
|
|
19
|
+
}
|
|
14
20
|
|
|
15
|
-
private var routeGroups: [Int:
|
|
21
|
+
private var routeGroups: [Int: Entry] = [:]
|
|
16
22
|
private var nextToken: Int = 1
|
|
17
23
|
private let lock = NSLock()
|
|
18
24
|
|
|
@@ -26,10 +32,18 @@ class IndependentRouteManager {
|
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
/// 存储路线组(使用指定 token)
|
|
29
|
-
func storeRouteGroup(token: Int, routeGroup: AMapNaviRouteGroup) {
|
|
35
|
+
func storeRouteGroup(token: Int, scene: String = "drive", routeGroup: AMapNaviRouteGroup) {
|
|
36
|
+
lock.lock()
|
|
37
|
+
defer { lock.unlock() }
|
|
38
|
+
let routeIds = routeGroup.naviRouteIDs?.map { $0.intValue } ?? []
|
|
39
|
+
routeGroups[token] = Entry(scene: scene, routeGroup: routeGroup, routeIds: routeIds)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// 存储非驾车场景的独立路径元信息
|
|
43
|
+
func storeSceneRoutes(token: Int, scene: String, routeIds: [Int]) {
|
|
30
44
|
lock.lock()
|
|
31
45
|
defer { lock.unlock() }
|
|
32
|
-
routeGroups[token] = routeGroup
|
|
46
|
+
routeGroups[token] = Entry(scene: scene, routeGroup: nil, routeIds: routeIds)
|
|
33
47
|
}
|
|
34
48
|
|
|
35
49
|
/// 存储路线组(自动生成 token)
|
|
@@ -38,7 +52,8 @@ class IndependentRouteManager {
|
|
|
38
52
|
defer { lock.unlock() }
|
|
39
53
|
let token = nextToken
|
|
40
54
|
nextToken += 1
|
|
41
|
-
|
|
55
|
+
let routeIds = routeGroup.naviRouteIDs?.map { $0.intValue } ?? []
|
|
56
|
+
routeGroups[token] = Entry(scene: "drive", routeGroup: routeGroup, routeIds: routeIds)
|
|
42
57
|
return token
|
|
43
58
|
}
|
|
44
59
|
|
|
@@ -46,7 +61,14 @@ class IndependentRouteManager {
|
|
|
46
61
|
func get(_ token: Int) -> AMapNaviRouteGroup? {
|
|
47
62
|
lock.lock()
|
|
48
63
|
defer { lock.unlock() }
|
|
49
|
-
return routeGroups[token]
|
|
64
|
+
return routeGroups[token]?.routeGroup
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// 获取路线场景
|
|
68
|
+
func scene(for token: Int) -> String? {
|
|
69
|
+
lock.lock()
|
|
70
|
+
defer { lock.unlock() }
|
|
71
|
+
return routeGroups[token]?.scene
|
|
50
72
|
}
|
|
51
73
|
|
|
52
74
|
/// 行前选路 - 选择指定路线
|
|
@@ -55,32 +77,45 @@ class IndependentRouteManager {
|
|
|
55
77
|
lock.lock()
|
|
56
78
|
defer { lock.unlock() }
|
|
57
79
|
|
|
58
|
-
guard let
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
80
|
+
guard let entry = routeGroups[token] else { return false }
|
|
81
|
+
|
|
82
|
+
let resolvedRouteId: Int? = {
|
|
83
|
+
if let routeId {
|
|
84
|
+
return routeId
|
|
85
|
+
}
|
|
86
|
+
if let routeIndex, routeIndex >= 0, routeIndex < entry.routeIds.count {
|
|
87
|
+
return entry.routeIds[routeIndex]
|
|
88
|
+
}
|
|
89
|
+
return nil
|
|
90
|
+
}()
|
|
91
|
+
|
|
92
|
+
guard let resolvedRouteId else {
|
|
93
|
+
return false
|
|
64
94
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
let routeId = routeIDs[routeIndex].intValue
|
|
69
|
-
routeGroup.selectNaviRoute(withRouteID: routeId)
|
|
95
|
+
|
|
96
|
+
if let routeGroup = entry.routeGroup {
|
|
97
|
+
routeGroup.selectNaviRoute(withRouteID: resolvedRouteId)
|
|
70
98
|
return true
|
|
71
99
|
}
|
|
72
|
-
|
|
73
|
-
|
|
100
|
+
|
|
101
|
+
switch entry.scene {
|
|
102
|
+
case "walk":
|
|
103
|
+
return AMapNaviWalkManager.sharedInstance().selectNaviRoute(withRouteID: resolvedRouteId)
|
|
104
|
+
case "ride":
|
|
105
|
+
return AMapNaviRideManager.sharedInstance().selectNaviRoute(withRouteID: resolvedRouteId)
|
|
106
|
+
default:
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
74
109
|
}
|
|
75
110
|
|
|
76
111
|
/// 启动导航
|
|
77
112
|
/// 官方方法:startGPSNavi: / startEmulatorNavi:
|
|
78
113
|
func start(token: Int, naviType: Int, routeId: Int?, routeIndex: Int?) -> Bool {
|
|
79
114
|
lock.lock()
|
|
80
|
-
let
|
|
115
|
+
let entry = routeGroups[token]
|
|
81
116
|
lock.unlock()
|
|
82
117
|
|
|
83
|
-
guard let
|
|
118
|
+
guard let entry = entry else { return false }
|
|
84
119
|
|
|
85
120
|
// 先选择路线
|
|
86
121
|
if routeId != nil || routeIndex != nil {
|
|
@@ -89,13 +124,41 @@ class IndependentRouteManager {
|
|
|
89
124
|
|
|
90
125
|
// 启动导航
|
|
91
126
|
// naviType: 0 = GPS导航, 1 = 模拟导航
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
127
|
+
switch entry.scene {
|
|
128
|
+
case "walk":
|
|
129
|
+
if let routeGroup = entry.routeGroup {
|
|
130
|
+
if naviType == 1 {
|
|
131
|
+
return AMapNaviWalkManager.sharedInstance().startEmulatorNavi(routeGroup)
|
|
132
|
+
} else {
|
|
133
|
+
return AMapNaviWalkManager.sharedInstance().startGPSNavi(routeGroup)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if naviType == 1 {
|
|
137
|
+
return AMapNaviWalkManager.sharedInstance().startEmulatorNavi()
|
|
138
|
+
} else {
|
|
139
|
+
return AMapNaviWalkManager.sharedInstance().startGPSNavi()
|
|
140
|
+
}
|
|
141
|
+
case "ride":
|
|
142
|
+
if let routeGroup = entry.routeGroup {
|
|
143
|
+
if naviType == 1 {
|
|
144
|
+
return AMapNaviRideManager.sharedInstance().startEmulatorNavi(routeGroup)
|
|
145
|
+
} else {
|
|
146
|
+
return AMapNaviRideManager.sharedInstance().startGPSNavi(routeGroup)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if naviType == 1 {
|
|
150
|
+
return AMapNaviRideManager.sharedInstance().startEmulatorNavi()
|
|
151
|
+
} else {
|
|
152
|
+
return AMapNaviRideManager.sharedInstance().startGPSNavi()
|
|
153
|
+
}
|
|
154
|
+
default:
|
|
155
|
+
guard let routeGroup = entry.routeGroup else { return false }
|
|
156
|
+
if naviType == 1 {
|
|
157
|
+
return AMapNaviDriveManager.sharedInstance().startEmulatorNavi(routeGroup)
|
|
158
|
+
} else {
|
|
159
|
+
return AMapNaviDriveManager.sharedInstance().startGPSNavi(routeGroup)
|
|
160
|
+
}
|
|
96
161
|
}
|
|
97
|
-
|
|
98
|
-
return true
|
|
99
162
|
}
|
|
100
163
|
|
|
101
164
|
/// 清除指定路线组
|
|
@@ -736,17 +736,31 @@ public class ExpoGaodeMapModule: Module {
|
|
|
736
736
|
promise.reject("FOREGROUND_PERMISSION_REQUIRED", "必须先授予前台位置权限才能请求后台位置权限")
|
|
737
737
|
return
|
|
738
738
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
"
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
739
|
+
|
|
740
|
+
if self.permissionManager == nil {
|
|
741
|
+
self.permissionManager = PermissionManager()
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
guard let permissionManager = self.permissionManager else {
|
|
745
|
+
promise.reject("PERMISSION_MANAGER_INIT_FAILED", "权限管理器初始化失败")
|
|
746
|
+
return
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
permissionManager.requestAlwaysPermission { _, _ in
|
|
750
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
751
|
+
let finalStatus = self.currentAuthorizationStatus()
|
|
752
|
+
let hasBackground = finalStatus == .authorizedAlways
|
|
753
|
+
|
|
754
|
+
promise.resolve([
|
|
755
|
+
"granted": hasBackground,
|
|
756
|
+
"backgroundLocation": hasBackground,
|
|
757
|
+
"status": self.getAuthorizationStatusString(finalStatus),
|
|
758
|
+
"message": hasBackground
|
|
759
|
+
? "已授予后台权限"
|
|
760
|
+
: "后台权限未授予,请在系统设置中将定位权限改为“始终允许”"
|
|
761
|
+
])
|
|
762
|
+
}
|
|
763
|
+
}
|
|
750
764
|
}
|
|
751
765
|
|
|
752
766
|
|
|
@@ -90,7 +90,16 @@ class LocationManager: NSObject, AMapLocationManagerDelegate {
|
|
|
90
90
|
return
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
ensureLocationManager()
|
|
93
|
+
guard let manager = ensureLocationManager() else {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
manager.allowsBackgroundLocationUpdates = allows
|
|
97
|
+
if #available(iOS 11.0, *) {
|
|
98
|
+
let indicatorSelector = NSSelectorFromString("setShowsBackgroundLocationIndicator:")
|
|
99
|
+
if manager.responds(to: indicatorSelector) {
|
|
100
|
+
manager.setValue(allows, forKey: "showsBackgroundLocationIndicator")
|
|
101
|
+
}
|
|
102
|
+
}
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
func setGeoLanguage(_ language: Int) {
|
|
@@ -39,6 +39,39 @@ class PermissionManager: NSObject, CLLocationManagerDelegate {
|
|
|
39
39
|
private var locationManager: CLLocationManager?
|
|
40
40
|
/// 权限请求回调
|
|
41
41
|
private var permissionCallback: ((Bool, String) -> Void)?
|
|
42
|
+
/// 后台(始终)权限请求回调
|
|
43
|
+
private var backgroundPermissionCallback: ((Bool, String) -> Void)?
|
|
44
|
+
/// 在 notDetermined 状态下,先申请前台权限,再升级为始终权限
|
|
45
|
+
private var pendingAlwaysAuthorizationUpgrade = false
|
|
46
|
+
|
|
47
|
+
private func resolveBackgroundPermissionIfNeeded(_ status: CLAuthorizationStatus) {
|
|
48
|
+
guard let backgroundPermissionCallback else {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
let backgroundGranted = status == .authorizedAlways
|
|
52
|
+
backgroundPermissionCallback(backgroundGranted, getAuthorizationStatusString(status))
|
|
53
|
+
self.backgroundPermissionCallback = nil
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private func scheduleAlwaysAuthorizationFallback(_ manager: CLLocationManager) {
|
|
57
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 1.2) { [weak self] in
|
|
58
|
+
guard let self else {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
guard self.backgroundPermissionCallback != nil else {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let latestStatus: CLAuthorizationStatus
|
|
66
|
+
if #available(iOS 14.0, *) {
|
|
67
|
+
latestStatus = manager.authorizationStatus
|
|
68
|
+
} else {
|
|
69
|
+
latestStatus = CLLocationManager.authorizationStatus()
|
|
70
|
+
}
|
|
71
|
+
self.pendingAlwaysAuthorizationUpgrade = false
|
|
72
|
+
self.resolveBackgroundPermissionIfNeeded(latestStatus)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
42
75
|
|
|
43
76
|
/**
|
|
44
77
|
* 请求位置权限
|
|
@@ -92,6 +125,61 @@ class PermissionManager: NSObject, CLLocationManagerDelegate {
|
|
|
92
125
|
locationManager.requestWhenInUseAuthorization()
|
|
93
126
|
}
|
|
94
127
|
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 请求后台(始终)位置权限
|
|
131
|
+
* @param callback 权限结果回调 (granted, status)
|
|
132
|
+
*/
|
|
133
|
+
func requestAlwaysPermission(callback: @escaping (Bool, String) -> Void) {
|
|
134
|
+
self.backgroundPermissionCallback = callback
|
|
135
|
+
|
|
136
|
+
DispatchQueue.main.async {
|
|
137
|
+
if self.locationManager == nil {
|
|
138
|
+
self.locationManager = CLLocationManager()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
guard let locationManager = self.locationManager else {
|
|
142
|
+
self.backgroundPermissionCallback?(false, "unknown")
|
|
143
|
+
self.backgroundPermissionCallback = nil
|
|
144
|
+
self.pendingAlwaysAuthorizationUpgrade = false
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
locationManager.delegate = self
|
|
149
|
+
|
|
150
|
+
let currentStatus: CLAuthorizationStatus
|
|
151
|
+
if #available(iOS 14.0, *) {
|
|
152
|
+
currentStatus = locationManager.authorizationStatus
|
|
153
|
+
} else {
|
|
154
|
+
currentStatus = CLLocationManager.authorizationStatus()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if currentStatus == .authorizedAlways {
|
|
158
|
+
self.backgroundPermissionCallback?(true, self.getAuthorizationStatusString(currentStatus))
|
|
159
|
+
self.backgroundPermissionCallback = nil
|
|
160
|
+
self.pendingAlwaysAuthorizationUpgrade = false
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if currentStatus == .denied || currentStatus == .restricted {
|
|
165
|
+
self.backgroundPermissionCallback?(false, self.getAuthorizationStatusString(currentStatus))
|
|
166
|
+
self.backgroundPermissionCallback = nil
|
|
167
|
+
self.pendingAlwaysAuthorizationUpgrade = false
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if currentStatus == .authorizedWhenInUse {
|
|
172
|
+
self.pendingAlwaysAuthorizationUpgrade = false
|
|
173
|
+
locationManager.requestAlwaysAuthorization()
|
|
174
|
+
self.scheduleAlwaysAuthorizationFallback(locationManager)
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// notDetermined: 先请求前台定位,再在回调中升级到始终权限
|
|
179
|
+
self.pendingAlwaysAuthorizationUpgrade = true
|
|
180
|
+
locationManager.requestWhenInUseAuthorization()
|
|
181
|
+
}
|
|
182
|
+
}
|
|
95
183
|
|
|
96
184
|
/**
|
|
97
185
|
* 权限状态变化回调 (iOS 14+)
|
|
@@ -115,6 +203,18 @@ class PermissionManager: NSObject, CLLocationManagerDelegate {
|
|
|
115
203
|
if status == .notDetermined {
|
|
116
204
|
return
|
|
117
205
|
}
|
|
206
|
+
|
|
207
|
+
if pendingAlwaysAuthorizationUpgrade && status == .authorizedWhenInUse {
|
|
208
|
+
pendingAlwaysAuthorizationUpgrade = false
|
|
209
|
+
if let locationManager {
|
|
210
|
+
locationManager.requestAlwaysAuthorization()
|
|
211
|
+
scheduleAlwaysAuthorizationFallback(locationManager)
|
|
212
|
+
} else {
|
|
213
|
+
resolveBackgroundPermissionIfNeeded(status)
|
|
214
|
+
}
|
|
215
|
+
return
|
|
216
|
+
}
|
|
217
|
+
pendingAlwaysAuthorizationUpgrade = false
|
|
118
218
|
|
|
119
219
|
// 状态已确定(授予或拒绝),返回结果
|
|
120
220
|
var granted = false
|
|
@@ -125,6 +225,8 @@ class PermissionManager: NSObject, CLLocationManagerDelegate {
|
|
|
125
225
|
}
|
|
126
226
|
let statusString = getAuthorizationStatusString(status)
|
|
127
227
|
|
|
228
|
+
resolveBackgroundPermissionIfNeeded(status)
|
|
229
|
+
|
|
128
230
|
permissionCallback?(granted, statusString)
|
|
129
231
|
permissionCallback = nil
|
|
130
232
|
}
|
|
@@ -236,6 +338,8 @@ class PermissionManager: NSObject, CLLocationManagerDelegate {
|
|
|
236
338
|
locationManager?.delegate = nil
|
|
237
339
|
locationManager = nil
|
|
238
340
|
permissionCallback = nil
|
|
341
|
+
backgroundPermissionCallback = nil
|
|
342
|
+
pendingAlwaysAuthorizationUpgrade = false
|
|
239
343
|
}
|
|
240
344
|
}
|
|
241
345
|
#endif
|