expo-gaode-map-navigation 2.0.9-next.0 → 2.0.9
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 +258 -3
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +4 -2
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNaviView.kt +931 -391
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNaviViewModule.kt +86 -1
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNavigationModule.kt +4 -5
- package/android/src/main/java/expo/modules/gaodemap/navigation/listeners/IndependentRouteListener.kt +4 -3
- package/android/src/main/java/expo/modules/gaodemap/navigation/listeners/RouteCalculateListener.kt +2 -2
- package/android/src/main/java/expo/modules/gaodemap/navigation/managers/IndependentRouteManager.kt +96 -14
- package/android/src/main/java/expo/modules/gaodemap/navigation/routes/drive/DriveTruckRouteCalculator.kt +2 -0
- package/android/src/main/java/expo/modules/gaodemap/navigation/utils/Converters.kt +19 -10
- package/android/src/main/res/drawable/landback_0.png +0 -0
- package/android/src/main/res/drawable/landback_1.png +0 -0
- package/android/src/main/res/drawable/landback_2.png +0 -0
- package/android/src/main/res/drawable/landback_3.png +0 -0
- package/android/src/main/res/drawable/landback_4.png +0 -0
- package/android/src/main/res/drawable/landback_5.png +0 -0
- package/android/src/main/res/drawable/landback_6.png +0 -0
- package/android/src/main/res/drawable/landback_7.png +0 -0
- package/android/src/main/res/drawable/landback_8.png +0 -0
- package/android/src/main/res/drawable/landback_9.png +0 -0
- package/android/src/main/res/drawable/landback_a.png +0 -0
- package/android/src/main/res/drawable/landback_b.png +0 -0
- package/android/src/main/res/drawable/landback_c.png +0 -0
- package/android/src/main/res/drawable/landback_d.png +0 -0
- package/android/src/main/res/drawable/landback_e.png +0 -0
- package/android/src/main/res/drawable/landback_f.png +0 -0
- package/android/src/main/res/drawable/landback_g.png +0 -0
- package/android/src/main/res/drawable/landback_h.png +0 -0
- package/android/src/main/res/drawable/landback_i.png +0 -0
- package/android/src/main/res/drawable/landback_j.png +0 -0
- package/android/src/main/res/drawable/landback_k.png +0 -0
- package/android/src/main/res/drawable/landback_l.png +0 -0
- package/android/src/main/res/drawable/landfront_0.png +0 -0
- package/android/src/main/res/drawable/landfront_00.png +0 -0
- package/android/src/main/res/drawable/landfront_1.png +0 -0
- package/android/src/main/res/drawable/landfront_11.png +0 -0
- package/android/src/main/res/drawable/landfront_20.png +0 -0
- package/android/src/main/res/drawable/landfront_21.png +0 -0
- package/android/src/main/res/drawable/landfront_22.png +0 -0
- package/android/src/main/res/drawable/landfront_3.png +0 -0
- package/android/src/main/res/drawable/landfront_33.png +0 -0
- package/android/src/main/res/drawable/landfront_40.png +0 -0
- package/android/src/main/res/drawable/landfront_43.png +0 -0
- package/android/src/main/res/drawable/landfront_44.png +0 -0
- package/android/src/main/res/drawable/landfront_5.png +0 -0
- package/android/src/main/res/drawable/landfront_55.png +0 -0
- package/android/src/main/res/drawable/landfront_61.png +0 -0
- package/android/src/main/res/drawable/landfront_63.png +0 -0
- package/android/src/main/res/drawable/landfront_66.png +0 -0
- package/android/src/main/res/drawable/landfront_70.png +0 -0
- package/android/src/main/res/drawable/landfront_71.png +0 -0
- package/android/src/main/res/drawable/landfront_73.png +0 -0
- package/android/src/main/res/drawable/landfront_77.png +0 -0
- package/android/src/main/res/drawable/landfront_8.png +0 -0
- package/android/src/main/res/drawable/landfront_88.png +0 -0
- package/android/src/main/res/drawable/landfront_90.png +0 -0
- package/android/src/main/res/drawable/landfront_95.png +0 -0
- package/android/src/main/res/drawable/landfront_99.png +0 -0
- package/android/src/main/res/drawable/landfront_a0.png +0 -0
- package/android/src/main/res/drawable/landfront_a8.png +0 -0
- package/android/src/main/res/drawable/landfront_aa.png +0 -0
- package/android/src/main/res/drawable/landfront_b1.png +0 -0
- package/android/src/main/res/drawable/landfront_b5.png +0 -0
- package/android/src/main/res/drawable/landfront_bb.png +0 -0
- package/android/src/main/res/drawable/landfront_c3.png +0 -0
- package/android/src/main/res/drawable/landfront_c8.png +0 -0
- package/android/src/main/res/drawable/landfront_cc.png +0 -0
- package/android/src/main/res/drawable/landfront_d.png +0 -0
- package/android/src/main/res/drawable/landfront_dd.png +0 -0
- package/android/src/main/res/drawable/landfront_e1.png +0 -0
- package/android/src/main/res/drawable/landfront_e5.png +0 -0
- package/android/src/main/res/drawable/landfront_ee.png +0 -0
- package/android/src/main/res/drawable/landfront_f0.png +0 -0
- package/android/src/main/res/drawable/landfront_f1.png +0 -0
- package/android/src/main/res/drawable/landfront_f5.png +0 -0
- package/android/src/main/res/drawable/landfront_ff.png +0 -0
- package/android/src/main/res/drawable/landfront_g3.png +0 -0
- package/android/src/main/res/drawable/landfront_g5.png +0 -0
- package/android/src/main/res/drawable/landfront_gg.png +0 -0
- package/android/src/main/res/drawable/landfront_h1.png +0 -0
- package/android/src/main/res/drawable/landfront_h3.png +0 -0
- package/android/src/main/res/drawable/landfront_h5.png +0 -0
- package/android/src/main/res/drawable/landfront_hh.png +0 -0
- package/android/src/main/res/drawable/landfront_i0.png +0 -0
- package/android/src/main/res/drawable/landfront_i3.png +0 -0
- package/android/src/main/res/drawable/landfront_i5.png +0 -0
- package/android/src/main/res/drawable/landfront_ii.png +0 -0
- package/android/src/main/res/drawable/landfront_j1.png +0 -0
- package/android/src/main/res/drawable/landfront_j8.png +0 -0
- package/android/src/main/res/drawable/landfront_jj.png +0 -0
- package/android/src/main/res/drawable/landfront_kk.png +0 -0
- package/android/src/main/res/drawable/landfront_ll.png +0 -0
- package/android/src/main/res/drawable/navi_arrow_leftline.png +0 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_center.xml +5 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_left.xml +8 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_over.xml +6 -0
- package/android/src/main/res/drawable/navi_lane_shape_bg_right.xml +8 -0
- package/build/ExpoGaodeMapNaviView.d.ts +8 -0
- package/build/ExpoGaodeMapNaviView.d.ts.map +1 -1
- package/build/ExpoGaodeMapNaviView.js +38 -1
- package/build/ExpoGaodeMapNaviView.js.map +1 -1
- package/build/index.d.ts +8 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +408 -4
- package/build/index.js.map +1 -1
- package/build/types/independent.types.d.ts +91 -0
- 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 +256 -12
- 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 +7 -1
- package/build/types/route.types.d.ts.map +1 -1
- package/build/types/route.types.js.map +1 -1
- package/ios/ExpoGaodeMapNaviView.swift +920 -67
- package/ios/ExpoGaodeMapNaviViewModule.swift +87 -1
- package/ios/ExpoGaodeMapNavigationModule.swift +90 -9
- package/ios/managers/IndependentRouteManager.swift +1 -0
- package/ios/map/ExpoGaodeMapModule.swift +9 -4
- package/ios/map/ExpoGaodeMapView.swift +13 -2
- package/ios/map/GaodeMapPrivacyManager.swift +23 -3
- package/ios/map/modules/LocationManager.swift +17 -0
- package/ios/map/utils/PermissionManager.swift +11 -6
- package/ios/routes/drive/DriveTruckRouteCalculator.swift +9 -0
- package/ios/routes/walkride/WalkRideRouteCalculator.swift +30 -0
- package/ios/services/IndependentRouteService.swift +211 -44
- package/package.json +16 -4
|
@@ -9,7 +9,183 @@ import Foundation
|
|
|
9
9
|
import ExpoModulesCore
|
|
10
10
|
import AMapNaviKit
|
|
11
11
|
|
|
12
|
+
final class ExpoGaodeMapCustomDriveView: AMapNaviDriveView {
|
|
13
|
+
var suppressLaneInfoUI: Bool = false
|
|
14
|
+
var suppressTopInfoUI: Bool = false {
|
|
15
|
+
didSet {
|
|
16
|
+
scheduleTopInfoSuppressionPasses()
|
|
17
|
+
setNeedsLayout()
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
private let topInfoCoverView: UIView = {
|
|
21
|
+
let view = UIView()
|
|
22
|
+
view.isHidden = true
|
|
23
|
+
view.isUserInteractionEnabled = false
|
|
24
|
+
view.backgroundColor = UIColor(red: 14.0 / 255.0, green: 18.0 / 255.0, blue: 26.0 / 255.0, alpha: 0.96)
|
|
25
|
+
return view
|
|
26
|
+
}()
|
|
27
|
+
private var scheduledSuppressionPasses = 0
|
|
28
|
+
|
|
29
|
+
override init(frame: CGRect) {
|
|
30
|
+
super.init(frame: frame)
|
|
31
|
+
installTopInfoCoverViewIfNeeded()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
required init?(coder: NSCoder) {
|
|
35
|
+
super.init(coder: coder)
|
|
36
|
+
installTopInfoCoverViewIfNeeded()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override func layoutSubviews() {
|
|
40
|
+
super.layoutSubviews()
|
|
41
|
+
applySuppressedChromeVisibility()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
override func didMoveToWindow() {
|
|
45
|
+
super.didMoveToWindow()
|
|
46
|
+
installTopInfoCoverViewIfNeeded()
|
|
47
|
+
if suppressTopInfoUI {
|
|
48
|
+
scheduleTopInfoSuppressionPasses()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override func driveManager(_ driveManager: AMapNaviDriveManager, showLaneBackInfo laneBackInfo: String, laneSelectInfo: String) {
|
|
53
|
+
guard !suppressLaneInfoUI else {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
super.driveManager(driveManager, showLaneBackInfo: laneBackInfo, laneSelectInfo: laneSelectInfo)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override func driveManagerHideLaneInfo(_ driveManager: AMapNaviDriveManager) {
|
|
60
|
+
guard !suppressLaneInfoUI else {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
super.driveManagerHideLaneInfo(driveManager)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private func applySuppressedChromeVisibility() {
|
|
67
|
+
installTopInfoCoverViewIfNeeded()
|
|
68
|
+
let topCandidates = collectTopInfoCandidates()
|
|
69
|
+
for candidate in topCandidates {
|
|
70
|
+
candidate.isHidden = suppressTopInfoUI
|
|
71
|
+
candidate.alpha = suppressTopInfoUI ? 0.0 : 1.0
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
guard suppressTopInfoUI, !topCandidates.isEmpty else {
|
|
75
|
+
topInfoCoverView.isHidden = true
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let unionFrame = topCandidates.reduce(CGRect.null) { partial, view in
|
|
80
|
+
let frame = view.convert(view.bounds, to: self)
|
|
81
|
+
return partial.union(frame)
|
|
82
|
+
}
|
|
83
|
+
let fallbackFrame = CGRect(x: 0, y: 0, width: bounds.width, height: min(max(bounds.height * 0.17, 96), 150))
|
|
84
|
+
let targetFrame = (unionFrame.isNull ? fallbackFrame : unionFrame.insetBy(dx: -8, dy: -6)).intersection(bounds)
|
|
85
|
+
topInfoCoverView.frame = targetFrame
|
|
86
|
+
topInfoCoverView.isHidden = targetFrame.isEmpty
|
|
87
|
+
if !topInfoCoverView.isHidden {
|
|
88
|
+
bringSubviewToFront(topInfoCoverView)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private func collectTopInfoCandidates() -> [UIView] {
|
|
93
|
+
guard suppressTopInfoUI || !subviews.isEmpty else {
|
|
94
|
+
return []
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let protectedClassNameFragments = [
|
|
98
|
+
"MAMap",
|
|
99
|
+
"Lane",
|
|
100
|
+
"Cross",
|
|
101
|
+
"Eagle",
|
|
102
|
+
"TrafficBar",
|
|
103
|
+
"Compass",
|
|
104
|
+
"Zoom",
|
|
105
|
+
"Scale",
|
|
106
|
+
"Logo",
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
return allDescendantSubviews(of: self).filter { view in
|
|
110
|
+
guard view !== self, view !== topInfoCoverView else {
|
|
111
|
+
return false
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let frame = view.convert(view.bounds, to: self)
|
|
115
|
+
guard !frame.isEmpty else {
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let className = NSStringFromClass(type(of: view))
|
|
120
|
+
if protectedClassNameFragments.contains(where: { className.localizedCaseInsensitiveContains($0) }) {
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let topBandMaxY = min(max(bounds.height * 0.28, 150), 220)
|
|
125
|
+
guard frame.minY <= topBandMaxY && frame.maxY <= topBandMaxY + 70 else {
|
|
126
|
+
return false
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
guard frame.height >= 12 && frame.height <= 140 && frame.width >= 20 else {
|
|
130
|
+
return false
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Keep small corner controls (for example compass / map tool buttons) out of the suppression set.
|
|
134
|
+
let isCornerControl =
|
|
135
|
+
frame.width <= 60 &&
|
|
136
|
+
frame.height <= 60 &&
|
|
137
|
+
(frame.minX <= 24 || frame.maxX >= bounds.width - 24)
|
|
138
|
+
if isCornerControl {
|
|
139
|
+
return false
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return true
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private func allDescendantSubviews(of root: UIView) -> [UIView] {
|
|
147
|
+
root.subviews.flatMap { subview in
|
|
148
|
+
[subview] + allDescendantSubviews(of: subview)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private func installTopInfoCoverViewIfNeeded() {
|
|
153
|
+
guard topInfoCoverView.superview !== self else {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
addSubview(topInfoCoverView)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private func scheduleTopInfoSuppressionPasses() {
|
|
160
|
+
scheduledSuppressionPasses = suppressTopInfoUI ? 18 : 0
|
|
161
|
+
guard suppressTopInfoUI else {
|
|
162
|
+
topInfoCoverView.isHidden = true
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
runScheduledTopInfoSuppressionPass()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private func runScheduledTopInfoSuppressionPass() {
|
|
169
|
+
applySuppressedChromeVisibility()
|
|
170
|
+
guard scheduledSuppressionPasses > 0 else {
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
scheduledSuppressionPasses -= 1
|
|
174
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.12) { [weak self] in
|
|
175
|
+
self?.runScheduledTopInfoSuppressionPass()
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func refreshSuppressedTopInfoUIIfNeeded() {
|
|
180
|
+
guard suppressTopInfoUI else {
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
applySuppressedChromeVisibility()
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
12
187
|
public class ExpoGaodeMapNaviView: ExpoView {
|
|
188
|
+
private let independentRouteManager = IndependentRouteManager.shared
|
|
13
189
|
|
|
14
190
|
// MARK: - 高德 SDK 初始化检查
|
|
15
191
|
|
|
@@ -68,6 +244,28 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
68
244
|
)
|
|
69
245
|
}
|
|
70
246
|
}
|
|
247
|
+
|
|
248
|
+
/// 检查 iOS 是否配置了后台定位模式(避免导航启动时触发系统异常)
|
|
249
|
+
private func ensureBackgroundLocationModeForNavigation() throws {
|
|
250
|
+
let backgroundModes = Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") as? [String]
|
|
251
|
+
guard backgroundModes?.contains("location") == true else {
|
|
252
|
+
throw NSError(
|
|
253
|
+
domain: "ExpoGaodeMapNaviView",
|
|
254
|
+
code: -1003,
|
|
255
|
+
userInfo: [
|
|
256
|
+
NSLocalizedDescriptionKey: "iOS 后台定位模式未开启,无法安全启动导航",
|
|
257
|
+
NSLocalizedFailureReasonErrorKey: "Info.plist 缺少 UIBackgroundModes: location",
|
|
258
|
+
NSLocalizedRecoverySuggestionErrorKey: """
|
|
259
|
+
请在 app.json 插件配置中开启后台定位后重新 prebuild:
|
|
260
|
+
["expo-gaode-map-navigation", {
|
|
261
|
+
"enableBackgroundLocation": true
|
|
262
|
+
}]
|
|
263
|
+
然后执行:npx expo prebuild --clean
|
|
264
|
+
"""
|
|
265
|
+
]
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
71
269
|
|
|
72
270
|
/// 格式化错误信息
|
|
73
271
|
private func formatError(_ error: Error) -> String {
|
|
@@ -99,15 +297,30 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
99
297
|
let onGpsStatusChanged = EventDispatcher()
|
|
100
298
|
let onNavigationInfoUpdate = EventDispatcher()
|
|
101
299
|
let onGpsSignalWeak = EventDispatcher()
|
|
300
|
+
let onNavigationVisualStateUpdate = EventDispatcher()
|
|
301
|
+
let onLaneInfoUpdate = EventDispatcher()
|
|
302
|
+
let onTrafficStatusesUpdate = EventDispatcher()
|
|
102
303
|
|
|
103
304
|
// MARK: - Properties
|
|
104
305
|
private var driveView: AMapNaviDriveView?
|
|
105
|
-
private var driveViewLoaded: Bool = false
|
|
106
306
|
private var pendingShowUIElements: Bool?
|
|
107
|
-
private var pendingShowUIElementsWorkItem: DispatchWorkItem?
|
|
108
307
|
private var hasStartedNavi: Bool = false
|
|
109
308
|
private var hasReceivedFirstNaviData: Bool = false
|
|
110
309
|
private var driveManager: AMapNaviDriveManager?
|
|
310
|
+
private var lastKnownSpeed: Int = 0
|
|
311
|
+
private var currentRouteTotalLength: Int?
|
|
312
|
+
private var lastNavigationInfoPayload: [String: Any]?
|
|
313
|
+
private var lastTurnIconType: Int?
|
|
314
|
+
private var lastNextTurnIconType: Int?
|
|
315
|
+
private var lastTurnIconImageUri: String?
|
|
316
|
+
private var lastNextTurnIconImageUri: String?
|
|
317
|
+
private var isCrossVisible: Bool = false
|
|
318
|
+
private var isLaneInfoVisible: Bool = false
|
|
319
|
+
|
|
320
|
+
private enum LaneStringKind {
|
|
321
|
+
case background
|
|
322
|
+
case selected
|
|
323
|
+
}
|
|
111
324
|
|
|
112
325
|
// Props - 通用属性
|
|
113
326
|
var naviType: Int = 0 // 0: GPS, 1: Emulator
|
|
@@ -117,6 +330,24 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
117
330
|
var showCamera: Bool = true {
|
|
118
331
|
didSet { applyShowCamera(showCamera) }
|
|
119
332
|
}
|
|
333
|
+
var carImageSource: String? {
|
|
334
|
+
didSet { applyCarImageSource() }
|
|
335
|
+
}
|
|
336
|
+
var carCompassImageSource: String? {
|
|
337
|
+
didSet { applyCarCompassImageSource() }
|
|
338
|
+
}
|
|
339
|
+
var startPointImageSource: String? {
|
|
340
|
+
didSet { applyStartPointImageSource() }
|
|
341
|
+
}
|
|
342
|
+
var wayPointImageSource: String? {
|
|
343
|
+
didSet { applyWayPointImageSource() }
|
|
344
|
+
}
|
|
345
|
+
var endPointImageSource: String? {
|
|
346
|
+
didSet { applyEndPointImageSource() }
|
|
347
|
+
}
|
|
348
|
+
var cameraImageSource: String? {
|
|
349
|
+
didSet { applyCameraImageSource() }
|
|
350
|
+
}
|
|
120
351
|
var autoLockCar: Bool = true {
|
|
121
352
|
didSet { applyAutoLockCar(autoLockCar) }
|
|
122
353
|
}
|
|
@@ -149,6 +380,12 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
149
380
|
var showTrafficBar: Bool = true {
|
|
150
381
|
didSet { driveView?.showTrafficBar = showTrafficBar }
|
|
151
382
|
}
|
|
383
|
+
var trafficBarFrame: CGRect = .zero {
|
|
384
|
+
didSet { applyTrafficBarFrame(trafficBarFrame) }
|
|
385
|
+
}
|
|
386
|
+
var trafficBarColors: [String: Any]? {
|
|
387
|
+
didSet { applyTrafficBarColors(trafficBarColors) }
|
|
388
|
+
}
|
|
152
389
|
var showBrowseRouteButton: Bool = true {
|
|
153
390
|
didSet { driveView?.showBrowseRouteButton = showBrowseRouteButton }
|
|
154
391
|
}
|
|
@@ -158,6 +395,12 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
158
395
|
var showTrafficButton: Bool = true {
|
|
159
396
|
didSet { driveView?.showTrafficButton = showTrafficButton }
|
|
160
397
|
}
|
|
398
|
+
var showBackupRoute: Bool = true {
|
|
399
|
+
didSet { driveView?.showBackupRoute = showBackupRoute }
|
|
400
|
+
}
|
|
401
|
+
var showEagleMap: Bool = false {
|
|
402
|
+
didSet { driveView?.showEagleMap = showEagleMap }
|
|
403
|
+
}
|
|
161
404
|
var showUIElements: Bool = true {
|
|
162
405
|
didSet { applyShowUIElementsToDriveViewIfReady() }
|
|
163
406
|
}
|
|
@@ -170,12 +413,43 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
170
413
|
var showTrafficLights: Bool = true {
|
|
171
414
|
didSet { driveView?.showTrafficLights = showTrafficLights }
|
|
172
415
|
}
|
|
416
|
+
var showCompassEnabled: Bool? {
|
|
417
|
+
didSet {
|
|
418
|
+
guard let showCompassEnabled else { return }
|
|
419
|
+
driveView?.showCompass = showCompassEnabled
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
var showDriveCongestion: Bool = true {
|
|
423
|
+
didSet { driveView?.showDriveCongestion = showDriveCongestion }
|
|
424
|
+
}
|
|
425
|
+
var showTrafficLightView: Bool = true {
|
|
426
|
+
didSet { driveView?.showTrafficLightView = showTrafficLightView }
|
|
427
|
+
}
|
|
173
428
|
var mapViewModeType: Int = 0 {
|
|
174
429
|
didSet { applyMapViewModeType(mapViewModeType) }
|
|
175
430
|
}
|
|
176
431
|
var lineWidth: CGFloat = 0 {
|
|
177
432
|
didSet { driveView?.lineWidth = lineWidth }
|
|
178
433
|
}
|
|
434
|
+
var driveViewEdgePadding: UIEdgeInsets = .zero {
|
|
435
|
+
didSet {
|
|
436
|
+
driveView?.setNeedsLayout()
|
|
437
|
+
driveView?.layoutIfNeeded()
|
|
438
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
var screenAnchor: CGPoint = .zero {
|
|
442
|
+
didSet {
|
|
443
|
+
driveView?.screenAnchor = screenAnchor
|
|
444
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
var hideNativeTopInfoLayout: Bool = false {
|
|
448
|
+
didSet { applyHideNativeTopInfoLayout(hideNativeTopInfoLayout) }
|
|
449
|
+
}
|
|
450
|
+
var hideNativeLaneInfoLayout: Bool = false {
|
|
451
|
+
didSet { applyHideNativeLaneInfoLayout(hideNativeLaneInfoLayout) }
|
|
452
|
+
}
|
|
179
453
|
|
|
180
454
|
func applyShowUIElements(_ visible: Bool) {
|
|
181
455
|
showUIElements = visible
|
|
@@ -216,13 +490,16 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
216
490
|
|
|
217
491
|
// 初始化驾车导航管理器
|
|
218
492
|
driveManager = AMapNaviDriveManager.sharedInstance()
|
|
219
|
-
|
|
493
|
+
rebindDriveManagerToView()
|
|
220
494
|
|
|
221
495
|
// 使用内置语音
|
|
222
496
|
driveManager?.isUseInternalTTS = true
|
|
223
497
|
|
|
224
498
|
// 初始化导航视图
|
|
225
|
-
|
|
499
|
+
let customDriveView = ExpoGaodeMapCustomDriveView(frame: bounds)
|
|
500
|
+
customDriveView.suppressTopInfoUI = hideNativeTopInfoLayout
|
|
501
|
+
customDriveView.suppressLaneInfoUI = hideNativeLaneInfoLayout
|
|
502
|
+
driveView = customDriveView
|
|
226
503
|
driveView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
227
504
|
driveView?.delegate = self
|
|
228
505
|
|
|
@@ -234,13 +511,233 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
234
511
|
// 应用初始配置
|
|
235
512
|
applyViewOptions()
|
|
236
513
|
}
|
|
514
|
+
|
|
515
|
+
private func rebindDriveManagerToView() {
|
|
516
|
+
driveManager = AMapNaviDriveManager.sharedInstance()
|
|
517
|
+
driveManager?.delegate = self
|
|
518
|
+
driveManager?.removeDataRepresentative(self)
|
|
519
|
+
if let view = driveView {
|
|
520
|
+
driveManager?.removeDataRepresentative(view)
|
|
521
|
+
driveManager?.addDataRepresentative(view)
|
|
522
|
+
}
|
|
523
|
+
driveManager?.addDataRepresentative(self)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
private func resetTransientNavigationState() {
|
|
527
|
+
lastNavigationInfoPayload = nil
|
|
528
|
+
lastTurnIconType = nil
|
|
529
|
+
lastNextTurnIconType = nil
|
|
530
|
+
clearCachedTurnIconUris()
|
|
531
|
+
isCrossVisible = false
|
|
532
|
+
isLaneInfoVisible = false
|
|
533
|
+
emitVisualStateUpdate()
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private func emitVisualStateUpdate() {
|
|
537
|
+
onNavigationVisualStateUpdate([
|
|
538
|
+
"isCrossVisible": isCrossVisible,
|
|
539
|
+
// iOS 官方导航 SDK 公开的是 showCrossImage / hideCrossImage,
|
|
540
|
+
// 当前没有 Android showModeCross / hideModeCross 对等的 3D 路口模型接口。
|
|
541
|
+
"isModeCrossVisible": false,
|
|
542
|
+
"isLaneInfoVisible": isLaneInfoVisible
|
|
543
|
+
])
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
private func emitNavigationInfoUpdate(_ payload: [String: Any]) {
|
|
547
|
+
(driveView as? ExpoGaodeMapCustomDriveView)?.refreshSuppressedTopInfoUIIfNeeded()
|
|
548
|
+
var nextPayload = payload
|
|
549
|
+
if let lastTurnIconType {
|
|
550
|
+
nextPayload["iconType"] = lastTurnIconType
|
|
551
|
+
nextPayload["iconDirection"] = lastTurnIconType
|
|
552
|
+
}
|
|
553
|
+
if let lastNextTurnIconType {
|
|
554
|
+
nextPayload["nextIconType"] = lastNextTurnIconType
|
|
555
|
+
}
|
|
556
|
+
if let lastTurnIconImageUri {
|
|
557
|
+
nextPayload["turnIconImage"] = lastTurnIconImageUri
|
|
558
|
+
} else {
|
|
559
|
+
nextPayload.removeValue(forKey: "turnIconImage")
|
|
560
|
+
}
|
|
561
|
+
if let lastNextTurnIconImageUri {
|
|
562
|
+
nextPayload["nextTurnIconImage"] = lastNextTurnIconImageUri
|
|
563
|
+
} else {
|
|
564
|
+
nextPayload.removeValue(forKey: "nextTurnIconImage")
|
|
565
|
+
}
|
|
566
|
+
if
|
|
567
|
+
let retainDistance = nextPayload["pathRetainDistance"] as? Int,
|
|
568
|
+
let driveDistance = nextPayload["driveDistance"] as? Int,
|
|
569
|
+
driveDistance > 0
|
|
570
|
+
{
|
|
571
|
+
currentRouteTotalLength = retainDistance + driveDistance
|
|
572
|
+
}
|
|
573
|
+
lastNavigationInfoPayload = nextPayload
|
|
574
|
+
onNavigationInfoUpdate(nextPayload)
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
private func reemitLastNavigationInfoIfNeeded() {
|
|
578
|
+
guard var nextPayload = lastNavigationInfoPayload else {
|
|
579
|
+
return
|
|
580
|
+
}
|
|
581
|
+
if let lastTurnIconType {
|
|
582
|
+
nextPayload["iconType"] = lastTurnIconType
|
|
583
|
+
nextPayload["iconDirection"] = lastTurnIconType
|
|
584
|
+
}
|
|
585
|
+
if let lastNextTurnIconType {
|
|
586
|
+
nextPayload["nextIconType"] = lastNextTurnIconType
|
|
587
|
+
} else {
|
|
588
|
+
nextPayload.removeValue(forKey: "nextIconType")
|
|
589
|
+
}
|
|
590
|
+
if let lastTurnIconImageUri {
|
|
591
|
+
nextPayload["turnIconImage"] = lastTurnIconImageUri
|
|
592
|
+
} else {
|
|
593
|
+
nextPayload.removeValue(forKey: "turnIconImage")
|
|
594
|
+
}
|
|
595
|
+
if let lastNextTurnIconImageUri {
|
|
596
|
+
nextPayload["nextTurnIconImage"] = lastNextTurnIconImageUri
|
|
597
|
+
} else {
|
|
598
|
+
nextPayload.removeValue(forKey: "nextTurnIconImage")
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
lastNavigationInfoPayload = nextPayload
|
|
602
|
+
onNavigationInfoUpdate(nextPayload)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
private func cacheTurnIconImage(_ image: UIImage?, prefix: String, previousUri: String?) -> String? {
|
|
606
|
+
guard let image, let data = image.pngData() else {
|
|
607
|
+
if let previousUri {
|
|
608
|
+
deleteCachedTurnIcon(at: previousUri)
|
|
609
|
+
}
|
|
610
|
+
return nil
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
let filename = "\(prefix)_\(UUID().uuidString).png"
|
|
614
|
+
let fileURL = FileManager.default.temporaryDirectory.appendingPathComponent(filename)
|
|
615
|
+
|
|
616
|
+
do {
|
|
617
|
+
try data.write(to: fileURL, options: .atomic)
|
|
618
|
+
if let previousUri, previousUri != fileURL.absoluteString {
|
|
619
|
+
deleteCachedTurnIcon(at: previousUri)
|
|
620
|
+
}
|
|
621
|
+
return fileURL.absoluteString
|
|
622
|
+
} catch {
|
|
623
|
+
return previousUri
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
private func deleteCachedTurnIcon(at uriString: String) {
|
|
628
|
+
guard let fileURL = URL(string: uriString), fileURL.isFileURL else {
|
|
629
|
+
return
|
|
630
|
+
}
|
|
631
|
+
try? FileManager.default.removeItem(at: fileURL)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
private func clearCachedTurnIconUris() {
|
|
635
|
+
if let lastTurnIconImageUri {
|
|
636
|
+
deleteCachedTurnIcon(at: lastTurnIconImageUri)
|
|
637
|
+
}
|
|
638
|
+
if let lastNextTurnIconImageUri {
|
|
639
|
+
deleteCachedTurnIcon(at: lastNextTurnIconImageUri)
|
|
640
|
+
}
|
|
641
|
+
lastTurnIconImageUri = nil
|
|
642
|
+
lastNextTurnIconImageUri = nil
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private func splitLaneInfoString(_ value: String) -> [String] {
|
|
646
|
+
value
|
|
647
|
+
.split(separator: "|", omittingEmptySubsequences: false)
|
|
648
|
+
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() }
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
private func parseLaneToken(_ token: String, kind: LaneStringKind) -> Int? {
|
|
652
|
+
guard !token.isEmpty else {
|
|
653
|
+
return nil
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
if token == "255" || token == "ff" {
|
|
657
|
+
return 255
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Older iOS callbacks may use `f` as filler / unavailable lane marker.
|
|
661
|
+
if token == "f" {
|
|
662
|
+
return kind == .background ? 255 : 255
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if let decimalValue = Int(token) {
|
|
666
|
+
return decimalValue
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
switch token {
|
|
670
|
+
case "a":
|
|
671
|
+
return 10
|
|
672
|
+
case "b":
|
|
673
|
+
return 11
|
|
674
|
+
case "c":
|
|
675
|
+
return 12
|
|
676
|
+
case "d":
|
|
677
|
+
return 13
|
|
678
|
+
case "e":
|
|
679
|
+
return 14
|
|
680
|
+
case "g":
|
|
681
|
+
return 16
|
|
682
|
+
case "h":
|
|
683
|
+
return 17
|
|
684
|
+
case "i":
|
|
685
|
+
return 18
|
|
686
|
+
case "j":
|
|
687
|
+
return 19
|
|
688
|
+
case "k":
|
|
689
|
+
return 20
|
|
690
|
+
case "kk":
|
|
691
|
+
return 21
|
|
692
|
+
case "l":
|
|
693
|
+
return 23
|
|
694
|
+
default:
|
|
695
|
+
return Int(token, radix: 16)
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
private func serializeLaneInfo(laneBackInfo: String, laneSelectInfo: String) -> [String: Any]? {
|
|
700
|
+
let backgroundLane = splitLaneInfoString(laneBackInfo).map {
|
|
701
|
+
parseLaneToken($0, kind: .background) ?? 255
|
|
702
|
+
}
|
|
703
|
+
let frontLane = splitLaneInfoString(laneSelectInfo).map {
|
|
704
|
+
parseLaneToken($0, kind: .selected) ?? 255
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
let sentinelIndex = backgroundLane.firstIndex(of: 255)
|
|
708
|
+
let resolvedCount = [
|
|
709
|
+
sentinelIndex,
|
|
710
|
+
backgroundLane.isEmpty ? nil : backgroundLane.count,
|
|
711
|
+
frontLane.isEmpty ? nil : frontLane.count
|
|
712
|
+
]
|
|
713
|
+
.compactMap { $0 }
|
|
714
|
+
.min() ?? 0
|
|
715
|
+
|
|
716
|
+
guard resolvedCount > 0 else {
|
|
717
|
+
return nil
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
let normalizedBackground = (0..<resolvedCount).map { index in
|
|
721
|
+
backgroundLane.indices.contains(index) ? backgroundLane[index] : 255
|
|
722
|
+
}
|
|
723
|
+
let normalizedFront = (0..<resolvedCount).map { index in
|
|
724
|
+
frontLane.indices.contains(index) ? frontLane[index] : 255
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return [
|
|
728
|
+
"laneCount": resolvedCount,
|
|
729
|
+
"backgroundLane": normalizedBackground,
|
|
730
|
+
"frontLane": normalizedFront
|
|
731
|
+
]
|
|
732
|
+
}
|
|
237
733
|
|
|
238
734
|
private func applyViewOptions() {
|
|
239
735
|
// 通用属性
|
|
736
|
+
driveView?.showUIElements = showUIElements
|
|
240
737
|
driveView?.showCamera = showCamera
|
|
241
738
|
driveView?.autoSwitchShowModeToCarPositionLocked = autoLockCar
|
|
242
739
|
driveView?.autoZoomMapLevel = autoChangeZoom
|
|
243
|
-
driveView?.
|
|
740
|
+
driveView?.mapShowTraffic = trafficLayerEnabled
|
|
244
741
|
driveView?.showCrossImage = realCrossDisplay
|
|
245
742
|
driveView?.trackingMode = naviMode == 0 ? .carNorth : .mapNorth
|
|
246
743
|
|
|
@@ -248,69 +745,275 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
248
745
|
driveView?.showRoute = showRoute
|
|
249
746
|
driveView?.showTurnArrow = showTurnArrow
|
|
250
747
|
driveView?.showTrafficBar = showTrafficBar
|
|
748
|
+
applyTrafficBarFrame(trafficBarFrame)
|
|
749
|
+
applyTrafficBarColors(trafficBarColors)
|
|
251
750
|
driveView?.showBrowseRouteButton = showBrowseRouteButton
|
|
252
751
|
driveView?.showMoreButton = showMoreButton
|
|
253
752
|
driveView?.showTrafficButton = showTrafficButton
|
|
753
|
+
driveView?.showBackupRoute = showBackupRoute
|
|
754
|
+
driveView?.showEagleMap = showEagleMap
|
|
254
755
|
driveView?.showGreyAfterPass = showGreyAfterPass
|
|
255
756
|
driveView?.showVectorline = showVectorline
|
|
256
757
|
driveView?.showTrafficLights = showTrafficLights
|
|
758
|
+
if let showCompassEnabled {
|
|
759
|
+
driveView?.showCompass = showCompassEnabled
|
|
760
|
+
}
|
|
761
|
+
driveView?.showDriveCongestion = showDriveCongestion
|
|
762
|
+
driveView?.showTrafficLightView = showTrafficLightView
|
|
257
763
|
if lineWidth > 0 {
|
|
258
764
|
driveView?.lineWidth = lineWidth
|
|
259
765
|
}
|
|
766
|
+
applyCustomAnnotationImages()
|
|
767
|
+
applyCustomUILayoutOptionsIfNeeded()
|
|
768
|
+
}
|
|
260
769
|
|
|
261
|
-
|
|
770
|
+
private func applyCustomAnnotationImages() {
|
|
771
|
+
applyCarImageSource()
|
|
772
|
+
applyCarCompassImageSource()
|
|
773
|
+
applyStartPointImageSource()
|
|
774
|
+
applyWayPointImageSource()
|
|
775
|
+
applyEndPointImageSource()
|
|
776
|
+
applyCameraImageSource()
|
|
262
777
|
}
|
|
263
778
|
|
|
264
|
-
private func
|
|
265
|
-
|
|
266
|
-
|
|
779
|
+
private func resolveLocalImage(_ source: String) -> UIImage? {
|
|
780
|
+
if source.hasPrefix("file://") {
|
|
781
|
+
let path = String(source.dropFirst(7))
|
|
782
|
+
return UIImage(contentsOfFile: path)
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
return UIImage(named: source) ?? UIImage(contentsOfFile: source)
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
private func applyAnnotationImage(
|
|
789
|
+
source: String?,
|
|
790
|
+
currentSource: @escaping () -> String?,
|
|
791
|
+
apply: @escaping (UIImage?) -> Void
|
|
792
|
+
) {
|
|
793
|
+
guard let source, !source.isEmpty else {
|
|
794
|
+
apply(nil)
|
|
267
795
|
return
|
|
268
796
|
}
|
|
269
797
|
|
|
270
|
-
|
|
271
|
-
|
|
798
|
+
if source.hasPrefix("http://") || source.hasPrefix("https://") {
|
|
799
|
+
DispatchQueue.global().async {
|
|
800
|
+
let image: UIImage? = {
|
|
801
|
+
guard let url = URL(string: source),
|
|
802
|
+
let data = try? Data(contentsOf: url) else {
|
|
803
|
+
return nil
|
|
804
|
+
}
|
|
805
|
+
return UIImage(data: data)
|
|
806
|
+
}()
|
|
807
|
+
|
|
808
|
+
DispatchQueue.main.async {
|
|
809
|
+
guard currentSource() == source else {
|
|
810
|
+
return
|
|
811
|
+
}
|
|
812
|
+
apply(image)
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
return
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
apply(resolveLocalImage(source))
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
private func applyCarImageSource() {
|
|
822
|
+
guard let driveView else {
|
|
823
|
+
return
|
|
824
|
+
}
|
|
825
|
+
applyAnnotationImage(source: carImageSource, currentSource: { [weak self] in
|
|
826
|
+
self?.carImageSource
|
|
827
|
+
}) { [weak driveView] image in
|
|
828
|
+
driveView?.setCarImage(image)
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
private func applyCarCompassImageSource() {
|
|
833
|
+
guard let driveView else {
|
|
272
834
|
return
|
|
273
835
|
}
|
|
836
|
+
applyAnnotationImage(source: carCompassImageSource, currentSource: { [weak self] in
|
|
837
|
+
self?.carCompassImageSource
|
|
838
|
+
}) { [weak driveView] image in
|
|
839
|
+
driveView?.setCarCompassImage(image)
|
|
840
|
+
}
|
|
841
|
+
}
|
|
274
842
|
|
|
843
|
+
private func applyStartPointImageSource() {
|
|
844
|
+
guard let driveView else {
|
|
845
|
+
return
|
|
846
|
+
}
|
|
847
|
+
applyAnnotationImage(source: startPointImageSource, currentSource: { [weak self] in
|
|
848
|
+
self?.startPointImageSource
|
|
849
|
+
}) { [weak driveView] image in
|
|
850
|
+
driveView?.setStartPointImage(image)
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
private func applyWayPointImageSource() {
|
|
855
|
+
guard let driveView else {
|
|
856
|
+
return
|
|
857
|
+
}
|
|
858
|
+
applyAnnotationImage(source: wayPointImageSource, currentSource: { [weak self] in
|
|
859
|
+
self?.wayPointImageSource
|
|
860
|
+
}) { [weak driveView] image in
|
|
861
|
+
driveView?.setWayPointImage(image)
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
private func applyEndPointImageSource() {
|
|
866
|
+
guard let driveView else {
|
|
867
|
+
return
|
|
868
|
+
}
|
|
869
|
+
applyAnnotationImage(source: endPointImageSource, currentSource: { [weak self] in
|
|
870
|
+
self?.endPointImageSource
|
|
871
|
+
}) { [weak driveView] image in
|
|
872
|
+
driveView?.setEndPointImage(image)
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
private func applyCameraImageSource() {
|
|
877
|
+
guard let driveView else {
|
|
878
|
+
return
|
|
879
|
+
}
|
|
880
|
+
applyAnnotationImage(source: cameraImageSource, currentSource: { [weak self] in
|
|
881
|
+
self?.cameraImageSource
|
|
882
|
+
}) { [weak driveView] image in
|
|
883
|
+
driveView?.setCameraImage(image)
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
private func applyShowUIElementsToDriveViewIfReady() {
|
|
888
|
+
guard let driveView else {
|
|
889
|
+
pendingShowUIElements = showUIElements
|
|
890
|
+
return
|
|
891
|
+
}
|
|
275
892
|
let value = pendingShowUIElements ?? showUIElements
|
|
276
893
|
pendingShowUIElements = nil
|
|
894
|
+
driveView.showUIElements = value
|
|
895
|
+
applyCustomUILayoutOptionsIfNeeded()
|
|
896
|
+
}
|
|
277
897
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
pendingShowUIElementsWorkItem?.cancel()
|
|
281
|
-
let workItem = DispatchWorkItem { [weak self] in
|
|
282
|
-
guard let self else { return }
|
|
283
|
-
self.applyDriveViewShowUIElements(true, remainingAttempts: 20)
|
|
284
|
-
}
|
|
285
|
-
pendingShowUIElementsWorkItem = workItem
|
|
286
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.08, execute: workItem)
|
|
898
|
+
private func applyCustomUILayoutOptionsIfNeeded() {
|
|
899
|
+
guard let driveView else {
|
|
287
900
|
return
|
|
288
901
|
}
|
|
289
902
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
guard let self else { return }
|
|
293
|
-
self.applyDriveViewShowUIElements(value, remainingAttempts: 20)
|
|
903
|
+
guard showUIElements == false else {
|
|
904
|
+
return
|
|
294
905
|
}
|
|
295
|
-
pendingShowUIElementsWorkItem = workItem
|
|
296
906
|
|
|
297
|
-
|
|
907
|
+
// In custom UI mode, these properties are controlled independently from
|
|
908
|
+
// the built-in widget layer and should be re-applied after toggling it off.
|
|
909
|
+
driveView.showCrossImage = realCrossDisplay
|
|
910
|
+
driveView.showTrafficBar = showTrafficBar
|
|
911
|
+
applyTrafficBarFrame(trafficBarFrame)
|
|
912
|
+
applyTrafficBarColors(trafficBarColors)
|
|
913
|
+
driveView.screenAnchor = screenAnchor
|
|
914
|
+
driveView.setNeedsLayout()
|
|
915
|
+
driveView.layoutIfNeeded()
|
|
916
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
298
917
|
}
|
|
299
918
|
|
|
300
|
-
private func
|
|
301
|
-
guard let driveView else {
|
|
919
|
+
private func refreshOverviewRouteVisibleRegionIfNeeded() {
|
|
920
|
+
guard showUIElements == false, let driveView else {
|
|
921
|
+
return
|
|
922
|
+
}
|
|
302
923
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
924
|
+
guard driveView.showMode == .overview else {
|
|
925
|
+
return
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
driveView.updateRoutePolylineInTheVisualRangeWhenTheShowModeIsOverview()
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
private func scheduleOverviewRouteVisibleRegionRefresh() {
|
|
932
|
+
DispatchQueue.main.async { [weak self] in
|
|
933
|
+
self?.driveView?.setNeedsLayout()
|
|
934
|
+
self?.driveView?.layoutIfNeeded()
|
|
935
|
+
self?.refreshOverviewRouteVisibleRegionIfNeeded()
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
private func applyHideNativeLaneInfoLayout(_ hidden: Bool) {
|
|
940
|
+
(driveView as? ExpoGaodeMapCustomDriveView)?.suppressLaneInfoUI = hidden
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
private func applyHideNativeTopInfoLayout(_ hidden: Bool) {
|
|
944
|
+
(driveView as? ExpoGaodeMapCustomDriveView)?.suppressTopInfoUI = hidden
|
|
945
|
+
driveView?.setNeedsLayout()
|
|
946
|
+
driveView?.layoutIfNeeded()
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
private func applyTrafficBarFrame(_ frame: CGRect) {
|
|
950
|
+
guard let driveView else {
|
|
951
|
+
return
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
guard frame.width > 0, frame.height > 0 else {
|
|
955
|
+
return
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
driveView.tmcRouteFrame = frame
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
private func applyTrafficBarColors(_ colors: [String: Any]?) {
|
|
962
|
+
guard let driveView, let colors else {
|
|
963
|
+
return
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
let mappings: [(String, AMapNaviRouteStatus)] = [
|
|
967
|
+
("unknown", .unknow),
|
|
968
|
+
("smooth", .smooth),
|
|
969
|
+
("fineOpen", .fineOpen),
|
|
970
|
+
("slow", .slow),
|
|
971
|
+
("jam", .jam),
|
|
972
|
+
("seriousJam", .seriousJam),
|
|
973
|
+
("defaultRoad", .default),
|
|
974
|
+
]
|
|
975
|
+
|
|
976
|
+
let resolvedColors = mappings.compactMap { key, status -> AMapNaviTMCStatusColor? in
|
|
977
|
+
guard let value = colors[key], let color = ColorParser.parseColor(value) else {
|
|
978
|
+
return nil
|
|
309
979
|
}
|
|
980
|
+
let item = AMapNaviTMCStatusColor()
|
|
981
|
+
item.status = status
|
|
982
|
+
item.color = color
|
|
983
|
+
return item
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
guard !resolvedColors.isEmpty else {
|
|
310
987
|
return
|
|
311
988
|
}
|
|
312
989
|
|
|
313
|
-
driveView.
|
|
990
|
+
driveView.tmcRouteColor = resolvedColors
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
private func emitTrafficStatusesUpdate(_ trafficStatuses: [AMapNaviTrafficStatus]?) {
|
|
994
|
+
// iOS 会提供 fineStatus;统一事件结构时保留它,方便 RN 自绘层按需细化颜色策略。
|
|
995
|
+
let items = (trafficStatuses ?? []).map { status in
|
|
996
|
+
var payload: [String: Any] = [
|
|
997
|
+
"status": Int(status.status.rawValue),
|
|
998
|
+
"length": status.length
|
|
999
|
+
]
|
|
1000
|
+
payload["fineStatus"] = status.trafficFineStatus
|
|
1001
|
+
return payload
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
var payload: [String: Any] = [
|
|
1005
|
+
"items": items
|
|
1006
|
+
]
|
|
1007
|
+
|
|
1008
|
+
if let totalLength = currentRouteTotalLength, totalLength > 0 {
|
|
1009
|
+
payload["totalLength"] = totalLength
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if let retainDistance = lastNavigationInfoPayload?["pathRetainDistance"] as? Int {
|
|
1013
|
+
payload["retainDistance"] = retainDistance
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
onTrafficStatusesUpdate(payload)
|
|
314
1017
|
}
|
|
315
1018
|
|
|
316
1019
|
// MARK: - Prop Setters
|
|
@@ -332,7 +1035,7 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
332
1035
|
}
|
|
333
1036
|
|
|
334
1037
|
private func applyTrafficLayerEnabled(_ enabled: Bool) {
|
|
335
|
-
driveView?.
|
|
1038
|
+
driveView?.mapShowTraffic = enabled
|
|
336
1039
|
}
|
|
337
1040
|
|
|
338
1041
|
private func applyRealCrossDisplay(_ enabled: Bool) {
|
|
@@ -355,6 +1058,7 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
355
1058
|
default:
|
|
356
1059
|
break
|
|
357
1060
|
}
|
|
1061
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
358
1062
|
}
|
|
359
1063
|
|
|
360
1064
|
private func applyNightMode(_ enabled: Bool) {
|
|
@@ -383,12 +1087,24 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
383
1087
|
do {
|
|
384
1088
|
try checkPrivacyReady()
|
|
385
1089
|
try checkAMapInitialization()
|
|
1090
|
+
try ensureBackgroundLocationModeForNavigation()
|
|
386
1091
|
} catch {
|
|
387
|
-
let
|
|
1092
|
+
let nsError = error as NSError
|
|
1093
|
+
let code: String
|
|
1094
|
+
if nsError.domain == "ExpoGaodeMapPrivacy" {
|
|
1095
|
+
code = "PRIVACY_NOT_AGREED"
|
|
1096
|
+
} else if nsError.code == -1003 {
|
|
1097
|
+
code = "BACKGROUND_LOCATION_NOT_ENABLED"
|
|
1098
|
+
} else {
|
|
1099
|
+
code = "AMAP_NOT_INITIALIZED"
|
|
1100
|
+
}
|
|
388
1101
|
promise.reject(code, formatError(error))
|
|
389
1102
|
return
|
|
390
1103
|
}
|
|
391
1104
|
|
|
1105
|
+
rebindDriveManagerToView()
|
|
1106
|
+
resetTransientNavigationState()
|
|
1107
|
+
|
|
392
1108
|
startCoordinate = AMapNaviPoint.location(withLatitude: CGFloat(startLat), longitude: CGFloat(startLng))
|
|
393
1109
|
endCoordinate = AMapNaviPoint.location(withLatitude: CGFloat(endLat), longitude: CGFloat(endLng))
|
|
394
1110
|
|
|
@@ -415,9 +1131,61 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
415
1131
|
promise.reject("CALCULATE_FAILED", "启动路线规划失败")
|
|
416
1132
|
}
|
|
417
1133
|
}
|
|
1134
|
+
|
|
1135
|
+
func startNavigationWithIndependentPath(
|
|
1136
|
+
token: Int,
|
|
1137
|
+
routeId: Int?,
|
|
1138
|
+
routeIndex: Int?,
|
|
1139
|
+
naviType: Int?,
|
|
1140
|
+
promise: Promise
|
|
1141
|
+
) {
|
|
1142
|
+
do {
|
|
1143
|
+
try checkPrivacyReady()
|
|
1144
|
+
try checkAMapInitialization()
|
|
1145
|
+
try ensureBackgroundLocationModeForNavigation()
|
|
1146
|
+
} catch {
|
|
1147
|
+
let nsError = error as NSError
|
|
1148
|
+
let code: String
|
|
1149
|
+
if nsError.domain == "ExpoGaodeMapPrivacy" {
|
|
1150
|
+
code = "PRIVACY_NOT_AGREED"
|
|
1151
|
+
} else if nsError.code == -1003 {
|
|
1152
|
+
code = "BACKGROUND_LOCATION_NOT_ENABLED"
|
|
1153
|
+
} else {
|
|
1154
|
+
code = "AMAP_NOT_INITIALIZED"
|
|
1155
|
+
}
|
|
1156
|
+
promise.reject(code, formatError(error))
|
|
1157
|
+
return
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
rebindDriveManagerToView()
|
|
1161
|
+
resetTransientNavigationState()
|
|
1162
|
+
|
|
1163
|
+
if let naviType {
|
|
1164
|
+
self.naviType = naviType
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
let ok = independentRouteManager.start(
|
|
1168
|
+
token: token,
|
|
1169
|
+
naviType: self.naviType,
|
|
1170
|
+
routeId: routeId,
|
|
1171
|
+
routeIndex: routeIndex
|
|
1172
|
+
)
|
|
1173
|
+
|
|
1174
|
+
if ok {
|
|
1175
|
+
promise.resolve([
|
|
1176
|
+
"success": true,
|
|
1177
|
+
"message": "独立路径导航启动中...",
|
|
1178
|
+
"token": token,
|
|
1179
|
+
"naviType": self.naviType
|
|
1180
|
+
])
|
|
1181
|
+
} else {
|
|
1182
|
+
promise.reject("START_INDEPENDENT_NAVI_FAILED", "独立路径导航启动失败")
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
418
1185
|
|
|
419
1186
|
func stopNavigation(promise: Promise) {
|
|
420
1187
|
driveManager?.stopNavi()
|
|
1188
|
+
resetTransientNavigationState()
|
|
421
1189
|
promise.resolve([
|
|
422
1190
|
"success": true,
|
|
423
1191
|
"message": "导航已停止"
|
|
@@ -435,6 +1203,7 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
435
1203
|
public override func layoutSubviews() {
|
|
436
1204
|
super.layoutSubviews()
|
|
437
1205
|
driveView?.frame = bounds
|
|
1206
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
438
1207
|
}
|
|
439
1208
|
|
|
440
1209
|
deinit {
|
|
@@ -442,7 +1211,9 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
442
1211
|
if let view = driveView {
|
|
443
1212
|
driveManager?.removeDataRepresentative(view)
|
|
444
1213
|
}
|
|
1214
|
+
driveManager?.removeDataRepresentative(self)
|
|
445
1215
|
driveManager?.delegate = nil
|
|
1216
|
+
clearCachedTurnIconUris()
|
|
446
1217
|
}
|
|
447
1218
|
}
|
|
448
1219
|
|
|
@@ -464,6 +1235,9 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
|
|
|
464
1235
|
}
|
|
465
1236
|
|
|
466
1237
|
applyShowUIElementsToDriveViewIfReady()
|
|
1238
|
+
DispatchQueue.main.async { [weak self] in
|
|
1239
|
+
self?.applyCustomAnnotationImages()
|
|
1240
|
+
}
|
|
467
1241
|
}
|
|
468
1242
|
|
|
469
1243
|
public func driveManager(_ driveManager: AMapNaviDriveManager, onCalculateRouteFailure error: Error) {
|
|
@@ -490,37 +1264,10 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
|
|
|
490
1264
|
}
|
|
491
1265
|
|
|
492
1266
|
public func driveManagerDidEndEmulatorNavi(_ driveManager: AMapNaviDriveManager) {
|
|
1267
|
+
resetTransientNavigationState()
|
|
493
1268
|
onNavigationEnded([:])
|
|
494
1269
|
}
|
|
495
1270
|
|
|
496
|
-
public func driveManager(_ driveManager: AMapNaviDriveManager, didUpdate naviLocation: AMapNaviLocation) {
|
|
497
|
-
if !hasReceivedFirstNaviData {
|
|
498
|
-
hasReceivedFirstNaviData = true
|
|
499
|
-
applyShowUIElementsToDriveViewIfReady()
|
|
500
|
-
}
|
|
501
|
-
onLocationUpdate([
|
|
502
|
-
"latitude": naviLocation.coordinate.latitude,
|
|
503
|
-
"longitude": naviLocation.coordinate.longitude,
|
|
504
|
-
"speed": naviLocation.speed,
|
|
505
|
-
"bearing": naviLocation.heading
|
|
506
|
-
])
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
public func driveManager(_ driveManager: AMapNaviDriveManager, didUpdate naviInfo: AMapNaviInfo) {
|
|
510
|
-
if !hasReceivedFirstNaviData {
|
|
511
|
-
hasReceivedFirstNaviData = true
|
|
512
|
-
applyShowUIElementsToDriveViewIfReady()
|
|
513
|
-
}
|
|
514
|
-
onNavigationInfoUpdate([
|
|
515
|
-
"currentRoadName": naviInfo.currentRoadName ?? "",
|
|
516
|
-
"nextRoadName": naviInfo.nextRoadName ?? "",
|
|
517
|
-
"pathRetainDistance": naviInfo.routeRemainDistance,
|
|
518
|
-
"pathRetainTime": naviInfo.routeRemainTime,
|
|
519
|
-
"curStepRetainDistance": naviInfo.segmentRemainDistance,
|
|
520
|
-
"curStepRetainTime": naviInfo.segmentRemainTime
|
|
521
|
-
])
|
|
522
|
-
}
|
|
523
|
-
|
|
524
1271
|
public func driveManager(_ driveManager: AMapNaviDriveManager, playNaviSound soundString: String, soundStringType: AMapNaviSoundType) {
|
|
525
1272
|
onNavigationText([
|
|
526
1273
|
"type": soundStringType.rawValue,
|
|
@@ -556,13 +1303,119 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
|
|
|
556
1303
|
extension ExpoGaodeMapNaviView: AMapNaviDriveViewDelegate {
|
|
557
1304
|
|
|
558
1305
|
public func driveViewDidLoad(_ driveView: AMapNaviDriveView) {
|
|
559
|
-
driveViewLoaded = true
|
|
560
1306
|
applyViewOptions()
|
|
561
1307
|
applyShowUIElementsToDriveViewIfReady()
|
|
1308
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
562
1309
|
onNavigationReady([:])
|
|
563
1310
|
}
|
|
564
1311
|
|
|
565
1312
|
public func driveViewEdgePadding(_ driveView: AMapNaviDriveView) -> UIEdgeInsets {
|
|
566
|
-
return
|
|
1313
|
+
return driveViewEdgePadding
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
public func driveView(_ driveView: AMapNaviDriveView, didChange showMode: AMapNaviDriveViewShowMode) {
|
|
1317
|
+
if showMode == .overview {
|
|
1318
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
extension ExpoGaodeMapNaviView: AMapNaviDriveDataRepresentable {
|
|
1324
|
+
public func driveManager(_ driveManager: AMapNaviDriveManager, update naviRoute: AMapNaviRoute?) {
|
|
1325
|
+
if let routeLength = naviRoute?.routeLength, routeLength > 0 {
|
|
1326
|
+
currentRouteTotalLength = routeLength
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
public func driveManager(_ driveManager: AMapNaviDriveManager, update naviLocation: AMapNaviLocation?) {
|
|
1331
|
+
guard let naviLocation else {
|
|
1332
|
+
return
|
|
1333
|
+
}
|
|
1334
|
+
if !hasReceivedFirstNaviData {
|
|
1335
|
+
hasReceivedFirstNaviData = true
|
|
1336
|
+
applyShowUIElementsToDriveViewIfReady()
|
|
1337
|
+
}
|
|
1338
|
+
lastKnownSpeed = Int(naviLocation.speed)
|
|
1339
|
+
onLocationUpdate([
|
|
1340
|
+
"latitude": naviLocation.coordinate.latitude,
|
|
1341
|
+
"longitude": naviLocation.coordinate.longitude,
|
|
1342
|
+
"speed": naviLocation.speed,
|
|
1343
|
+
"bearing": naviLocation.heading
|
|
1344
|
+
])
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
public func driveManager(_ driveManager: AMapNaviDriveManager, update naviInfo: AMapNaviInfo?) {
|
|
1348
|
+
guard let naviInfo else {
|
|
1349
|
+
return
|
|
1350
|
+
}
|
|
1351
|
+
if !hasReceivedFirstNaviData {
|
|
1352
|
+
hasReceivedFirstNaviData = true
|
|
1353
|
+
applyShowUIElementsToDriveViewIfReady()
|
|
1354
|
+
}
|
|
1355
|
+
emitNavigationInfoUpdate([
|
|
1356
|
+
"naviMode": naviInfo.naviMode.rawValue,
|
|
1357
|
+
"currentRoadName": naviInfo.currentRoadName ?? "",
|
|
1358
|
+
"nextRoadName": naviInfo.nextRoadName ?? "",
|
|
1359
|
+
"pathRetainDistance": naviInfo.routeRemainDistance,
|
|
1360
|
+
"pathRetainTime": naviInfo.routeRemainTime,
|
|
1361
|
+
"curStepRetainDistance": naviInfo.segmentRemainDistance,
|
|
1362
|
+
"curStepRetainTime": naviInfo.segmentRemainTime,
|
|
1363
|
+
"currentSpeed": lastKnownSpeed,
|
|
1364
|
+
"iconType": lastTurnIconType ?? naviInfo.iconType.rawValue,
|
|
1365
|
+
"iconDirection": lastTurnIconType ?? naviInfo.iconType.rawValue,
|
|
1366
|
+
"currentSegmentIndex": naviInfo.currentSegmentIndex,
|
|
1367
|
+
"currentLinkIndex": naviInfo.currentLinkIndex,
|
|
1368
|
+
"currentPointIndex": naviInfo.currentPointIndex,
|
|
1369
|
+
"routeRemainTrafficLightCount": naviInfo.routeRemainTrafficLightCount,
|
|
1370
|
+
"driveDistance": naviInfo.routeDriveDistance,
|
|
1371
|
+
"driveTime": naviInfo.routeDriveTime
|
|
1372
|
+
])
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
public func driveManager(_ driveManager: AMapNaviDriveManager, showCross crossImage: UIImage?) {
|
|
1376
|
+
isCrossVisible = true
|
|
1377
|
+
emitVisualStateUpdate()
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
public func driveManagerHideCrossImage(_ driveManager: AMapNaviDriveManager) {
|
|
1381
|
+
isCrossVisible = false
|
|
1382
|
+
emitVisualStateUpdate()
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
public func driveManager(_ driveManager: AMapNaviDriveManager, showLaneBackInfo laneBackInfo: String, laneSelectInfo: String) {
|
|
1386
|
+
isLaneInfoVisible = true
|
|
1387
|
+
emitVisualStateUpdate()
|
|
1388
|
+
if let payload = serializeLaneInfo(laneBackInfo: laneBackInfo, laneSelectInfo: laneSelectInfo) {
|
|
1389
|
+
onLaneInfoUpdate(payload)
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
public func driveManagerHideLaneInfo(_ driveManager: AMapNaviDriveManager) {
|
|
1394
|
+
isLaneInfoVisible = false
|
|
1395
|
+
emitVisualStateUpdate()
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
public func driveManager(_ driveManager: AMapNaviDriveManager, updateTrafficStatus trafficStatus: [AMapNaviTrafficStatus]?) {
|
|
1399
|
+
emitTrafficStatusesUpdate(trafficStatus)
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
public func driveManager(_ driveManager: AMapNaviDriveManager, updateTurnIconImage turnIconImage: UIImage?, turn turnIconType: AMapNaviIconType) {
|
|
1403
|
+
lastTurnIconType = Int(turnIconType.rawValue)
|
|
1404
|
+
lastTurnIconImageUri = cacheTurnIconImage(
|
|
1405
|
+
turnIconImage,
|
|
1406
|
+
prefix: "turn_icon",
|
|
1407
|
+
previousUri: lastTurnIconImageUri
|
|
1408
|
+
)
|
|
1409
|
+
reemitLastNavigationInfoIfNeeded()
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
public func driveManager(_ driveManager: AMapNaviDriveManager, updateNextTurnIconImage turnIconImage: UIImage?, nextTurn turnIconType: AMapNaviIconType) {
|
|
1413
|
+
lastNextTurnIconType = Int(turnIconType.rawValue)
|
|
1414
|
+
lastNextTurnIconImageUri = cacheTurnIconImage(
|
|
1415
|
+
turnIconImage,
|
|
1416
|
+
prefix: "next_turn_icon",
|
|
1417
|
+
previousUri: lastNextTurnIconImageUri
|
|
1418
|
+
)
|
|
1419
|
+
reemitLastNavigationInfoIfNeeded()
|
|
567
1420
|
}
|
|
568
1421
|
}
|