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
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import Foundation
|
|
9
9
|
import ExpoModulesCore
|
|
10
10
|
import AMapNaviKit
|
|
11
|
+
import AVFAudio
|
|
12
|
+
import CoreLocation
|
|
11
13
|
|
|
12
14
|
final class ExpoGaodeMapCustomDriveView: AMapNaviDriveView {
|
|
13
15
|
var suppressLaneInfoUI: Bool = false
|
|
@@ -17,6 +19,12 @@ final class ExpoGaodeMapCustomDriveView: AMapNaviDriveView {
|
|
|
17
19
|
setNeedsLayout()
|
|
18
20
|
}
|
|
19
21
|
}
|
|
22
|
+
var suppressBottomRightUI: Bool = false {
|
|
23
|
+
didSet {
|
|
24
|
+
scheduleTopInfoSuppressionPasses()
|
|
25
|
+
setNeedsLayout()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
20
28
|
private let topInfoCoverView: UIView = {
|
|
21
29
|
let view = UIView()
|
|
22
30
|
view.isHidden = true
|
|
@@ -71,6 +79,12 @@ final class ExpoGaodeMapCustomDriveView: AMapNaviDriveView {
|
|
|
71
79
|
candidate.alpha = suppressTopInfoUI ? 0.0 : 1.0
|
|
72
80
|
}
|
|
73
81
|
|
|
82
|
+
let bottomRightCandidates = collectBottomRightCandidates()
|
|
83
|
+
for candidate in bottomRightCandidates {
|
|
84
|
+
candidate.isHidden = suppressBottomRightUI
|
|
85
|
+
candidate.alpha = suppressBottomRightUI ? 0.0 : 1.0
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
guard suppressTopInfoUI, !topCandidates.isEmpty else {
|
|
75
89
|
topInfoCoverView.isHidden = true
|
|
76
90
|
return
|
|
@@ -143,6 +157,58 @@ final class ExpoGaodeMapCustomDriveView: AMapNaviDriveView {
|
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
159
|
|
|
160
|
+
private func collectBottomRightCandidates() -> [UIView] {
|
|
161
|
+
guard suppressBottomRightUI || !subviews.isEmpty else {
|
|
162
|
+
return []
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let protectedClassNameFragments = [
|
|
166
|
+
"MAMap",
|
|
167
|
+
"Lane",
|
|
168
|
+
"Cross",
|
|
169
|
+
"Eagle",
|
|
170
|
+
"TrafficBar",
|
|
171
|
+
"Compass",
|
|
172
|
+
"Zoom",
|
|
173
|
+
"Scale",
|
|
174
|
+
"Logo",
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
return allDescendantSubviews(of: self).filter { view in
|
|
178
|
+
guard view !== self, view !== topInfoCoverView else {
|
|
179
|
+
return false
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let frame = view.convert(view.bounds, to: self)
|
|
183
|
+
guard !frame.isEmpty else {
|
|
184
|
+
return false
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let className = NSStringFromClass(type(of: view))
|
|
188
|
+
if protectedClassNameFragments.contains(where: { className.localizedCaseInsensitiveContains($0) }) {
|
|
189
|
+
return false
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
guard frame.minX >= bounds.width * 0.76 || frame.maxX >= bounds.width - 10 else {
|
|
193
|
+
return false
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
guard frame.minY >= bounds.height * 0.46 else {
|
|
197
|
+
return false
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
guard frame.width >= 18 && frame.width <= 110 else {
|
|
201
|
+
return false
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
guard frame.height >= 18 && frame.height <= 240 else {
|
|
205
|
+
return false
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return true
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
146
212
|
private func allDescendantSubviews(of root: UIView) -> [UIView] {
|
|
147
213
|
root.subviews.flatMap { subview in
|
|
148
214
|
[subview] + allDescendantSubviews(of: subview)
|
|
@@ -157,8 +223,8 @@ final class ExpoGaodeMapCustomDriveView: AMapNaviDriveView {
|
|
|
157
223
|
}
|
|
158
224
|
|
|
159
225
|
private func scheduleTopInfoSuppressionPasses() {
|
|
160
|
-
scheduledSuppressionPasses = suppressTopInfoUI ? 18 : 0
|
|
161
|
-
guard suppressTopInfoUI else {
|
|
226
|
+
scheduledSuppressionPasses = (suppressTopInfoUI || suppressBottomRightUI) ? 18 : 0
|
|
227
|
+
guard suppressTopInfoUI || suppressBottomRightUI else {
|
|
162
228
|
topInfoCoverView.isHidden = true
|
|
163
229
|
return
|
|
164
230
|
}
|
|
@@ -177,13 +243,55 @@ final class ExpoGaodeMapCustomDriveView: AMapNaviDriveView {
|
|
|
177
243
|
}
|
|
178
244
|
|
|
179
245
|
func refreshSuppressedTopInfoUIIfNeeded() {
|
|
180
|
-
guard suppressTopInfoUI else {
|
|
246
|
+
guard suppressTopInfoUI || suppressBottomRightUI else {
|
|
181
247
|
return
|
|
182
248
|
}
|
|
183
249
|
applySuppressedChromeVisibility()
|
|
184
250
|
}
|
|
185
251
|
}
|
|
186
252
|
|
|
253
|
+
private struct NaviCustomWaypointMarkerModel {
|
|
254
|
+
let latitude: Double
|
|
255
|
+
let longitude: Double
|
|
256
|
+
let title: String
|
|
257
|
+
var arrived: Bool = false
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private final class NaviCustomWaypointBubbleView: UIView {
|
|
261
|
+
init(title: String) {
|
|
262
|
+
let font = UIFont.systemFont(ofSize: 17, weight: .semibold)
|
|
263
|
+
let textWidth = ceil((title as NSString).size(withAttributes: [.font: font]).width)
|
|
264
|
+
let bodyWidth = min(max(textWidth + 28, 62), 110)
|
|
265
|
+
let size = CGSize(width: bodyWidth, height: 34)
|
|
266
|
+
super.init(frame: CGRect(origin: .zero, size: size))
|
|
267
|
+
|
|
268
|
+
backgroundColor = .clear
|
|
269
|
+
isOpaque = false
|
|
270
|
+
|
|
271
|
+
let bodyView = UIView(frame: bounds)
|
|
272
|
+
bodyView.backgroundColor = UIColor(red: 47.0 / 255.0, green: 103.0 / 255.0, blue: 255.0 / 255.0, alpha: 1)
|
|
273
|
+
bodyView.layer.cornerRadius = 17
|
|
274
|
+
bodyView.layer.borderWidth = 2
|
|
275
|
+
bodyView.layer.borderColor = UIColor.white.cgColor
|
|
276
|
+
bodyView.layer.shadowColor = UIColor(red: 21.0 / 255.0, green: 53.0 / 255.0, blue: 127.0 / 255.0, alpha: 1).cgColor
|
|
277
|
+
bodyView.layer.shadowOpacity = 0.18
|
|
278
|
+
bodyView.layer.shadowRadius = 6
|
|
279
|
+
bodyView.layer.shadowOffset = CGSize(width: 0, height: 3)
|
|
280
|
+
addSubview(bodyView)
|
|
281
|
+
|
|
282
|
+
let label = UILabel(frame: bodyView.bounds.insetBy(dx: 10, dy: 4))
|
|
283
|
+
label.text = title
|
|
284
|
+
label.textAlignment = .center
|
|
285
|
+
label.textColor = .white
|
|
286
|
+
label.font = font
|
|
287
|
+
bodyView.addSubview(label)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
required init?(coder: NSCoder) {
|
|
291
|
+
fatalError("init(coder:) has not been implemented")
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
187
295
|
public class ExpoGaodeMapNaviView: ExpoView {
|
|
188
296
|
private let independentRouteManager = IndependentRouteManager.shared
|
|
189
297
|
|
|
@@ -302,11 +410,22 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
302
410
|
let onTrafficStatusesUpdate = EventDispatcher()
|
|
303
411
|
|
|
304
412
|
// MARK: - Properties
|
|
413
|
+
private enum NaviScene: String {
|
|
414
|
+
case drive
|
|
415
|
+
case walk
|
|
416
|
+
case ride
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
private var activeScene: NaviScene = .drive
|
|
305
420
|
private var driveView: AMapNaviDriveView?
|
|
421
|
+
private var walkView: AMapNaviWalkView?
|
|
422
|
+
private var rideView: AMapNaviRideView?
|
|
306
423
|
private var pendingShowUIElements: Bool?
|
|
307
424
|
private var hasStartedNavi: Bool = false
|
|
308
425
|
private var hasReceivedFirstNaviData: Bool = false
|
|
309
426
|
private var driveManager: AMapNaviDriveManager?
|
|
427
|
+
private var walkManager: AMapNaviWalkManager?
|
|
428
|
+
private var rideManager: AMapNaviRideManager?
|
|
310
429
|
private var lastKnownSpeed: Int = 0
|
|
311
430
|
private var currentRouteTotalLength: Int?
|
|
312
431
|
private var lastNavigationInfoPayload: [String: Any]?
|
|
@@ -314,8 +433,14 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
314
433
|
private var lastNextTurnIconType: Int?
|
|
315
434
|
private var lastTurnIconImageUri: String?
|
|
316
435
|
private var lastNextTurnIconImageUri: String?
|
|
436
|
+
private var lastTurnIconBase64: String?
|
|
437
|
+
private var trafficBarTotalLength: Int?
|
|
317
438
|
private var isCrossVisible: Bool = false
|
|
318
439
|
private var isLaneInfoVisible: Bool = false
|
|
440
|
+
private var isNavigationAudioSessionActive: Bool = false
|
|
441
|
+
private var hasLoggedMissingBackgroundAudioMode: Bool = false
|
|
442
|
+
private var renderedCustomWaypointAnnotations: [AMapNaviCompositeCustomAnnotation] = []
|
|
443
|
+
private var customWaypointMarkers: [NaviCustomWaypointMarkerModel] = []
|
|
319
444
|
|
|
320
445
|
private enum LaneStringKind {
|
|
321
446
|
case background
|
|
@@ -333,6 +458,9 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
333
458
|
var carImageSource: String? {
|
|
334
459
|
didSet { applyCarImageSource() }
|
|
335
460
|
}
|
|
461
|
+
var carImageSize: CGSize? {
|
|
462
|
+
didSet { applyCarImageSource() }
|
|
463
|
+
}
|
|
336
464
|
var carCompassImageSource: String? {
|
|
337
465
|
didSet { applyCarCompassImageSource() }
|
|
338
466
|
}
|
|
@@ -342,6 +470,9 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
342
470
|
var wayPointImageSource: String? {
|
|
343
471
|
didSet { applyWayPointImageSource() }
|
|
344
472
|
}
|
|
473
|
+
var customWaypointMarkerPayloads: [[String: Any]]? {
|
|
474
|
+
didSet { applyCustomWaypointMarkerPayloads(customWaypointMarkerPayloads) }
|
|
475
|
+
}
|
|
345
476
|
var endPointImageSource: String? {
|
|
346
477
|
didSet { applyEndPointImageSource() }
|
|
347
478
|
}
|
|
@@ -375,7 +506,7 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
375
506
|
didSet { driveView?.showRoute = showRoute }
|
|
376
507
|
}
|
|
377
508
|
var showTurnArrow: Bool = true {
|
|
378
|
-
didSet {
|
|
509
|
+
didSet { applyShowTurnArrow(showTurnArrow) }
|
|
379
510
|
}
|
|
380
511
|
var showTrafficBar: Bool = true {
|
|
381
512
|
didSet { driveView?.showTrafficBar = showTrafficBar }
|
|
@@ -387,10 +518,10 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
387
518
|
didSet { applyTrafficBarColors(trafficBarColors) }
|
|
388
519
|
}
|
|
389
520
|
var showBrowseRouteButton: Bool = true {
|
|
390
|
-
didSet {
|
|
521
|
+
didSet { applyShowBrowseRouteButton(showBrowseRouteButton) }
|
|
391
522
|
}
|
|
392
523
|
var showMoreButton: Bool = true {
|
|
393
|
-
didSet {
|
|
524
|
+
didSet { applyShowMoreButton(showMoreButton) }
|
|
394
525
|
}
|
|
395
526
|
var showTrafficButton: Bool = true {
|
|
396
527
|
didSet { driveView?.showTrafficButton = showTrafficButton }
|
|
@@ -402,10 +533,10 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
402
533
|
didSet { driveView?.showEagleMap = showEagleMap }
|
|
403
534
|
}
|
|
404
535
|
var showUIElements: Bool = true {
|
|
405
|
-
didSet {
|
|
536
|
+
didSet { applyShowUIElementsToActiveViewIfReady() }
|
|
406
537
|
}
|
|
407
|
-
var showGreyAfterPass: Bool =
|
|
408
|
-
didSet {
|
|
538
|
+
var showGreyAfterPass: Bool = true {
|
|
539
|
+
didSet { applyShowGreyAfterPass(showGreyAfterPass) }
|
|
409
540
|
}
|
|
410
541
|
var showVectorline: Bool = true {
|
|
411
542
|
didSet { driveView?.showVectorline = showVectorline }
|
|
@@ -416,7 +547,7 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
416
547
|
var showCompassEnabled: Bool? {
|
|
417
548
|
didSet {
|
|
418
549
|
guard let showCompassEnabled else { return }
|
|
419
|
-
|
|
550
|
+
applyShowCompassEnabled(showCompassEnabled)
|
|
420
551
|
}
|
|
421
552
|
}
|
|
422
553
|
var showDriveCongestion: Bool = true {
|
|
@@ -429,18 +560,18 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
429
560
|
didSet { applyMapViewModeType(mapViewModeType) }
|
|
430
561
|
}
|
|
431
562
|
var lineWidth: CGFloat = 0 {
|
|
432
|
-
didSet {
|
|
563
|
+
didSet { applyLineWidth(lineWidth) }
|
|
433
564
|
}
|
|
434
565
|
var driveViewEdgePadding: UIEdgeInsets = .zero {
|
|
435
566
|
didSet {
|
|
436
|
-
|
|
437
|
-
|
|
567
|
+
currentNaviView()?.setNeedsLayout()
|
|
568
|
+
currentNaviView()?.layoutIfNeeded()
|
|
438
569
|
scheduleOverviewRouteVisibleRegionRefresh()
|
|
439
570
|
}
|
|
440
571
|
}
|
|
441
572
|
var screenAnchor: CGPoint = .zero {
|
|
442
573
|
didSet {
|
|
443
|
-
|
|
574
|
+
applyScreenAnchor(screenAnchor)
|
|
444
575
|
scheduleOverviewRouteVisibleRegionRefresh()
|
|
445
576
|
}
|
|
446
577
|
}
|
|
@@ -450,6 +581,15 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
450
581
|
var hideNativeLaneInfoLayout: Bool = false {
|
|
451
582
|
didSet { applyHideNativeLaneInfoLayout(hideNativeLaneInfoLayout) }
|
|
452
583
|
}
|
|
584
|
+
var iosLiveActivityEnabled: Bool = false {
|
|
585
|
+
didSet {
|
|
586
|
+
if iosLiveActivityEnabled {
|
|
587
|
+
syncNavigationLiveActivityWithLastPayload()
|
|
588
|
+
} else {
|
|
589
|
+
NavigationLiveActivityManager.shared.stop()
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
453
593
|
|
|
454
594
|
func applyShowUIElements(_ visible: Bool) {
|
|
455
595
|
showUIElements = visible
|
|
@@ -487,34 +627,164 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
487
627
|
}
|
|
488
628
|
return
|
|
489
629
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
630
|
+
|
|
631
|
+
switchToScene(.drive)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
private func currentNaviView() -> UIView? {
|
|
635
|
+
switch activeScene {
|
|
636
|
+
case .drive:
|
|
637
|
+
return driveView
|
|
638
|
+
case .walk:
|
|
639
|
+
return walkView
|
|
640
|
+
case .ride:
|
|
641
|
+
return rideView
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private func currentNaviManager() -> AMapNaviBaseManager? {
|
|
646
|
+
switch activeScene {
|
|
647
|
+
case .drive:
|
|
648
|
+
return driveManager
|
|
649
|
+
case .walk:
|
|
650
|
+
return walkManager
|
|
651
|
+
case .ride:
|
|
652
|
+
return rideManager
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
private func setupDriveViewIfNeeded() {
|
|
657
|
+
guard driveView == nil else {
|
|
658
|
+
return
|
|
659
|
+
}
|
|
499
660
|
let customDriveView = ExpoGaodeMapCustomDriveView(frame: bounds)
|
|
661
|
+
customDriveView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
662
|
+
customDriveView.delegate = self
|
|
500
663
|
customDriveView.suppressTopInfoUI = hideNativeTopInfoLayout
|
|
501
664
|
customDriveView.suppressLaneInfoUI = hideNativeLaneInfoLayout
|
|
502
665
|
driveView = customDriveView
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
driveManager?.addDataRepresentative(view)
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
private func setupWalkViewIfNeeded() {
|
|
669
|
+
guard walkView == nil else {
|
|
670
|
+
return
|
|
509
671
|
}
|
|
510
|
-
|
|
511
|
-
|
|
672
|
+
let view = AMapNaviWalkView(frame: bounds)
|
|
673
|
+
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
674
|
+
view.delegate = self
|
|
675
|
+
walkView = view
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
private func setupRideViewIfNeeded() {
|
|
679
|
+
guard rideView == nil else {
|
|
680
|
+
return
|
|
681
|
+
}
|
|
682
|
+
let view = AMapNaviRideView(frame: bounds)
|
|
683
|
+
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
684
|
+
view.delegate = self
|
|
685
|
+
rideView = view
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
private func attachActiveView(_ targetView: UIView?) {
|
|
689
|
+
let knownViews = [driveView, walkView, rideView].compactMap { $0 }
|
|
690
|
+
for view in knownViews where view !== targetView {
|
|
691
|
+
if view.superview === self {
|
|
692
|
+
view.removeFromSuperview()
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
guard let targetView else {
|
|
697
|
+
return
|
|
698
|
+
}
|
|
699
|
+
targetView.frame = bounds
|
|
700
|
+
if targetView.superview !== self {
|
|
701
|
+
addSubview(targetView)
|
|
702
|
+
}
|
|
703
|
+
sendSubviewToBack(targetView)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
private func switchToScene(_ scene: NaviScene) {
|
|
707
|
+
teardownManagers(except: scene)
|
|
708
|
+
activeScene = scene
|
|
709
|
+
|
|
710
|
+
switch scene {
|
|
711
|
+
case .drive:
|
|
712
|
+
setupDriveViewIfNeeded()
|
|
713
|
+
rebindDriveManagerToView()
|
|
714
|
+
attachActiveView(driveView)
|
|
715
|
+
case .walk:
|
|
716
|
+
setupWalkViewIfNeeded()
|
|
717
|
+
rebindWalkManagerToView()
|
|
718
|
+
attachActiveView(walkView)
|
|
719
|
+
case .ride:
|
|
720
|
+
setupRideViewIfNeeded()
|
|
721
|
+
rebindRideManagerToView()
|
|
722
|
+
attachActiveView(rideView)
|
|
723
|
+
}
|
|
724
|
+
|
|
512
725
|
applyViewOptions()
|
|
726
|
+
applyShowUIElementsToActiveViewIfReady()
|
|
727
|
+
DispatchQueue.main.async { [weak self] in
|
|
728
|
+
self?.onNavigationReady([:])
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
private func teardownManagers(except scene: NaviScene) {
|
|
733
|
+
if scene != .drive {
|
|
734
|
+
destroyDriveManagerIfNeeded()
|
|
735
|
+
}
|
|
736
|
+
if scene != .walk {
|
|
737
|
+
destroyWalkManagerIfNeeded()
|
|
738
|
+
}
|
|
739
|
+
if scene != .ride {
|
|
740
|
+
destroyRideManagerIfNeeded()
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
private func destroyDriveManagerIfNeeded() {
|
|
745
|
+
guard let driveManager else {
|
|
746
|
+
return
|
|
747
|
+
}
|
|
748
|
+
if let view = driveView {
|
|
749
|
+
driveManager.removeDataRepresentative(view)
|
|
750
|
+
}
|
|
751
|
+
driveManager.removeDataRepresentative(self)
|
|
752
|
+
driveManager.delegate = nil
|
|
753
|
+
self.driveManager = nil
|
|
754
|
+
_ = AMapNaviDriveManager.destroyInstance()
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
private func destroyWalkManagerIfNeeded() {
|
|
758
|
+
guard let walkManager else {
|
|
759
|
+
return
|
|
760
|
+
}
|
|
761
|
+
if let view = walkView {
|
|
762
|
+
walkManager.removeDataRepresentative(view)
|
|
763
|
+
}
|
|
764
|
+
walkManager.removeDataRepresentative(self)
|
|
765
|
+
walkManager.delegate = nil
|
|
766
|
+
self.walkManager = nil
|
|
767
|
+
_ = AMapNaviWalkManager.destroyInstance()
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
private func destroyRideManagerIfNeeded() {
|
|
771
|
+
guard let rideManager else {
|
|
772
|
+
return
|
|
773
|
+
}
|
|
774
|
+
if let view = rideView {
|
|
775
|
+
rideManager.removeDataRepresentative(view)
|
|
776
|
+
}
|
|
777
|
+
rideManager.removeDataRepresentative(self)
|
|
778
|
+
rideManager.delegate = nil
|
|
779
|
+
self.rideManager = nil
|
|
780
|
+
_ = AMapNaviRideManager.destroyInstance()
|
|
513
781
|
}
|
|
514
782
|
|
|
515
783
|
private func rebindDriveManagerToView() {
|
|
516
784
|
driveManager = AMapNaviDriveManager.sharedInstance()
|
|
517
785
|
driveManager?.delegate = self
|
|
786
|
+
applyDriveManagerBackgroundLocationOptionsIfNeeded()
|
|
787
|
+
driveManager?.isUseInternalTTS = enableVoice
|
|
518
788
|
driveManager?.removeDataRepresentative(self)
|
|
519
789
|
if let view = driveView {
|
|
520
790
|
driveManager?.removeDataRepresentative(view)
|
|
@@ -523,14 +793,137 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
523
793
|
driveManager?.addDataRepresentative(self)
|
|
524
794
|
}
|
|
525
795
|
|
|
796
|
+
private func rebindWalkManagerToView() {
|
|
797
|
+
walkManager = AMapNaviWalkManager.sharedInstance()
|
|
798
|
+
walkManager?.delegate = self
|
|
799
|
+
applyWalkManagerBackgroundLocationOptionsIfNeeded()
|
|
800
|
+
walkManager?.isUseInternalTTS = enableVoice
|
|
801
|
+
walkManager?.removeDataRepresentative(self)
|
|
802
|
+
if let view = walkView {
|
|
803
|
+
walkManager?.removeDataRepresentative(view)
|
|
804
|
+
walkManager?.addDataRepresentative(view)
|
|
805
|
+
}
|
|
806
|
+
walkManager?.addDataRepresentative(self)
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
private func rebindRideManagerToView() {
|
|
810
|
+
rideManager = AMapNaviRideManager.sharedInstance()
|
|
811
|
+
rideManager?.delegate = self
|
|
812
|
+
applyRideManagerBackgroundLocationOptionsIfNeeded()
|
|
813
|
+
rideManager?.isUseInternalTTS = enableVoice
|
|
814
|
+
rideManager?.removeDataRepresentative(self)
|
|
815
|
+
if let view = rideView {
|
|
816
|
+
rideManager?.removeDataRepresentative(view)
|
|
817
|
+
rideManager?.addDataRepresentative(view)
|
|
818
|
+
}
|
|
819
|
+
rideManager?.addDataRepresentative(self)
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
private func applyDriveManagerBackgroundLocationOptionsIfNeeded() {
|
|
823
|
+
guard let driveManager else {
|
|
824
|
+
return
|
|
825
|
+
}
|
|
826
|
+
driveManager.pausesLocationUpdatesAutomatically = false
|
|
827
|
+
let backgroundModes = Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") as? [String]
|
|
828
|
+
if backgroundModes?.contains("location") == true {
|
|
829
|
+
driveManager.allowsBackgroundLocationUpdates = true
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
private func applyWalkManagerBackgroundLocationOptionsIfNeeded() {
|
|
834
|
+
guard let walkManager else {
|
|
835
|
+
return
|
|
836
|
+
}
|
|
837
|
+
walkManager.pausesLocationUpdatesAutomatically = false
|
|
838
|
+
let backgroundModes = Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") as? [String]
|
|
839
|
+
if backgroundModes?.contains("location") == true {
|
|
840
|
+
walkManager.allowsBackgroundLocationUpdates = true
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
private func applyRideManagerBackgroundLocationOptionsIfNeeded() {
|
|
845
|
+
guard let rideManager else {
|
|
846
|
+
return
|
|
847
|
+
}
|
|
848
|
+
rideManager.pausesLocationUpdatesAutomatically = false
|
|
849
|
+
let backgroundModes = Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") as? [String]
|
|
850
|
+
if backgroundModes?.contains("location") == true {
|
|
851
|
+
rideManager.allowsBackgroundLocationUpdates = true
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
private func hasBackgroundAudioModeEnabled() -> Bool {
|
|
856
|
+
let backgroundModes = Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") as? [String]
|
|
857
|
+
return backgroundModes?.contains("audio") == true
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
private func activateNavigationAudioSessionIfNeeded(reason: String) {
|
|
861
|
+
guard enableVoice else {
|
|
862
|
+
return
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
if !hasBackgroundAudioModeEnabled(), !hasLoggedMissingBackgroundAudioMode {
|
|
866
|
+
hasLoggedMissingBackgroundAudioMode = true
|
|
867
|
+
NSLog(
|
|
868
|
+
"[ExpoGaodeMapNaviView][Audio] UIBackgroundModes 缺少 audio,切后台后语音可能中断。reason=%@",
|
|
869
|
+
reason
|
|
870
|
+
)
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
let audioSession = AVAudioSession.sharedInstance()
|
|
874
|
+
do {
|
|
875
|
+
try audioSession.setCategory(
|
|
876
|
+
.playback,
|
|
877
|
+
mode: .voicePrompt,
|
|
878
|
+
options: [.duckOthers, .allowBluetooth, .allowBluetoothA2DP]
|
|
879
|
+
)
|
|
880
|
+
try audioSession.setActive(true)
|
|
881
|
+
isNavigationAudioSessionActive = true
|
|
882
|
+
NSLog("[ExpoGaodeMapNaviView][Audio] activated. reason=%@", reason)
|
|
883
|
+
} catch {
|
|
884
|
+
NSLog(
|
|
885
|
+
"[ExpoGaodeMapNaviView][Audio] activate failed. reason=%@ error=%@",
|
|
886
|
+
reason,
|
|
887
|
+
String(describing: error)
|
|
888
|
+
)
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
private func deactivateNavigationAudioSessionIfNeeded(reason: String) {
|
|
893
|
+
guard isNavigationAudioSessionActive else {
|
|
894
|
+
return
|
|
895
|
+
}
|
|
896
|
+
let audioSession = AVAudioSession.sharedInstance()
|
|
897
|
+
do {
|
|
898
|
+
try audioSession.setActive(false, options: [.notifyOthersOnDeactivation])
|
|
899
|
+
isNavigationAudioSessionActive = false
|
|
900
|
+
NSLog("[ExpoGaodeMapNaviView][Audio] deactivated. reason=%@", reason)
|
|
901
|
+
} catch {
|
|
902
|
+
NSLog(
|
|
903
|
+
"[ExpoGaodeMapNaviView][Audio] deactivate failed. reason=%@ error=%@",
|
|
904
|
+
reason,
|
|
905
|
+
String(describing: error)
|
|
906
|
+
)
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
526
910
|
private func resetTransientNavigationState() {
|
|
911
|
+
hasStartedNavi = false
|
|
912
|
+
hasReceivedFirstNaviData = false
|
|
913
|
+
lastKnownSpeed = 0
|
|
914
|
+
currentRouteTotalLength = nil
|
|
915
|
+
trafficBarTotalLength = nil
|
|
527
916
|
lastNavigationInfoPayload = nil
|
|
528
917
|
lastTurnIconType = nil
|
|
529
918
|
lastNextTurnIconType = nil
|
|
919
|
+
lastTurnIconBase64 = nil
|
|
530
920
|
clearCachedTurnIconUris()
|
|
531
921
|
isCrossVisible = false
|
|
532
922
|
isLaneInfoVisible = false
|
|
923
|
+
resetCustomWaypointArrivalState()
|
|
533
924
|
emitVisualStateUpdate()
|
|
925
|
+
NavigationLiveActivityManager.shared.stop()
|
|
926
|
+
deactivateNavigationAudioSessionIfNeeded(reason: "reset_transient_navigation_state")
|
|
534
927
|
}
|
|
535
928
|
|
|
536
929
|
private func emitVisualStateUpdate() {
|
|
@@ -546,11 +939,13 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
546
939
|
private func emitNavigationInfoUpdate(_ payload: [String: Any]) {
|
|
547
940
|
(driveView as? ExpoGaodeMapCustomDriveView)?.refreshSuppressedTopInfoUIIfNeeded()
|
|
548
941
|
var nextPayload = payload
|
|
549
|
-
|
|
942
|
+
let payloadIconType = payloadIntValue(nextPayload["iconType"]) ?? 0
|
|
943
|
+
if payloadIconType <= 0, let lastTurnIconType {
|
|
550
944
|
nextPayload["iconType"] = lastTurnIconType
|
|
551
945
|
nextPayload["iconDirection"] = lastTurnIconType
|
|
552
946
|
}
|
|
553
|
-
|
|
947
|
+
let payloadNextIconType = payloadIntValue(nextPayload["nextIconType"]) ?? 0
|
|
948
|
+
if payloadNextIconType <= 0, let lastNextTurnIconType {
|
|
554
949
|
nextPayload["nextIconType"] = lastNextTurnIconType
|
|
555
950
|
}
|
|
556
951
|
if let lastTurnIconImageUri {
|
|
@@ -563,15 +958,9 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
563
958
|
} else {
|
|
564
959
|
nextPayload.removeValue(forKey: "nextTurnIconImage")
|
|
565
960
|
}
|
|
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
961
|
lastNavigationInfoPayload = nextPayload
|
|
574
962
|
onNavigationInfoUpdate(nextPayload)
|
|
963
|
+
syncNavigationLiveActivity(payload: nextPayload)
|
|
575
964
|
}
|
|
576
965
|
|
|
577
966
|
private func reemitLastNavigationInfoIfNeeded() {
|
|
@@ -600,77 +989,338 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
600
989
|
|
|
601
990
|
lastNavigationInfoPayload = nextPayload
|
|
602
991
|
onNavigationInfoUpdate(nextPayload)
|
|
992
|
+
syncNavigationLiveActivity(payload: nextPayload)
|
|
603
993
|
}
|
|
604
994
|
|
|
605
|
-
private func
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
995
|
+
private func resolveAppDisplayName() -> String {
|
|
996
|
+
let info = Bundle.main.infoDictionary
|
|
997
|
+
if let displayName = info?["CFBundleDisplayName"] as? String, !displayName.isEmpty {
|
|
998
|
+
return displayName
|
|
999
|
+
}
|
|
1000
|
+
if let appName = info?["CFBundleName"] as? String, !appName.isEmpty {
|
|
1001
|
+
return appName
|
|
611
1002
|
}
|
|
1003
|
+
return "导航"
|
|
1004
|
+
}
|
|
612
1005
|
|
|
613
|
-
|
|
614
|
-
let
|
|
1006
|
+
private func payloadIntValue(_ value: Any?) -> Int? {
|
|
1007
|
+
if let intValue = value as? Int {
|
|
1008
|
+
return intValue
|
|
1009
|
+
}
|
|
1010
|
+
if let numberValue = value as? NSNumber {
|
|
1011
|
+
return numberValue.intValue
|
|
1012
|
+
}
|
|
1013
|
+
if let doubleValue = value as? Double {
|
|
1014
|
+
return Int(doubleValue)
|
|
1015
|
+
}
|
|
1016
|
+
if let floatValue = value as? Float {
|
|
1017
|
+
return Int(floatValue)
|
|
1018
|
+
}
|
|
1019
|
+
return nil
|
|
1020
|
+
}
|
|
615
1021
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
deleteCachedTurnIcon(at: previousUri)
|
|
620
|
-
}
|
|
621
|
-
return fileURL.absoluteString
|
|
622
|
-
} catch {
|
|
623
|
-
return previousUri
|
|
1022
|
+
private func makeLiveActivitySnapshot(payload: [String: Any]?) -> NavigationLiveActivitySnapshot? {
|
|
1023
|
+
guard let payload else {
|
|
1024
|
+
return nil
|
|
624
1025
|
}
|
|
1026
|
+
|
|
1027
|
+
let remainDistance = payloadIntValue(payload["pathRetainDistance"]) ?? 0
|
|
1028
|
+
let routeTotalDistance = max(
|
|
1029
|
+
trafficBarTotalLength ?? 0,
|
|
1030
|
+
currentRouteTotalLength ?? 0,
|
|
1031
|
+
remainDistance
|
|
1032
|
+
)
|
|
1033
|
+
let remainTime = payloadIntValue(payload["pathRetainTime"]) ?? 0
|
|
1034
|
+
let stepRemainDistance = payloadIntValue(payload["curStepRetainDistance"]) ?? 0
|
|
1035
|
+
let iconType = payloadIntValue(payload["iconType"]) ?? 0
|
|
1036
|
+
let currentRoadName = (payload["currentRoadName"] as? String) ?? ""
|
|
1037
|
+
let nextRoadName = (payload["nextRoadName"] as? String) ?? ""
|
|
1038
|
+
|
|
1039
|
+
return NavigationLiveActivitySnapshot(
|
|
1040
|
+
appName: resolveAppDisplayName(),
|
|
1041
|
+
currentRoadName: currentRoadName,
|
|
1042
|
+
nextRoadName: nextRoadName,
|
|
1043
|
+
pathRetainDistance: remainDistance,
|
|
1044
|
+
routeTotalDistance: routeTotalDistance,
|
|
1045
|
+
pathRetainTime: remainTime,
|
|
1046
|
+
curStepRetainDistance: stepRemainDistance,
|
|
1047
|
+
iconType: iconType,
|
|
1048
|
+
turnIconBase64: lastTurnIconBase64
|
|
1049
|
+
)
|
|
625
1050
|
}
|
|
626
1051
|
|
|
627
|
-
private func
|
|
628
|
-
guard
|
|
1052
|
+
private func syncNavigationLiveActivity(payload: [String: Any]?) {
|
|
1053
|
+
guard iosLiveActivityEnabled else {
|
|
629
1054
|
return
|
|
630
1055
|
}
|
|
631
|
-
|
|
1056
|
+
guard hasStartedNavi else {
|
|
1057
|
+
return
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
guard let snapshot = makeLiveActivitySnapshot(payload: payload) else {
|
|
1061
|
+
return
|
|
1062
|
+
}
|
|
1063
|
+
NavigationLiveActivityManager.shared.startOrUpdate(snapshot: snapshot)
|
|
632
1064
|
}
|
|
633
1065
|
|
|
634
|
-
private func
|
|
635
|
-
|
|
636
|
-
|
|
1066
|
+
private func syncNavigationLiveActivityWithLastPayload() {
|
|
1067
|
+
syncNavigationLiveActivity(payload: lastNavigationInfoPayload)
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
private func normalizedTurnIconImage(_ image: UIImage) -> UIImage {
|
|
1071
|
+
guard image.imageOrientation != .up else {
|
|
1072
|
+
return image
|
|
637
1073
|
}
|
|
638
|
-
|
|
639
|
-
|
|
1074
|
+
let renderer = UIGraphicsImageRenderer(size: image.size)
|
|
1075
|
+
return renderer.image { _ in
|
|
1076
|
+
image.draw(in: CGRect(origin: .zero, size: image.size))
|
|
640
1077
|
}
|
|
641
|
-
lastTurnIconImageUri = nil
|
|
642
|
-
lastNextTurnIconImageUri = nil
|
|
643
1078
|
}
|
|
644
1079
|
|
|
645
|
-
private func
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
1080
|
+
private func trimmedTransparentBoundsImage(_ image: UIImage) -> UIImage {
|
|
1081
|
+
guard let cgImage = image.cgImage else {
|
|
1082
|
+
return image
|
|
1083
|
+
}
|
|
1084
|
+
guard let dataProvider = cgImage.dataProvider, let data = dataProvider.data else {
|
|
1085
|
+
return image
|
|
1086
|
+
}
|
|
650
1087
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
1088
|
+
let bytes = CFDataGetBytePtr(data)
|
|
1089
|
+
let bytesPerPixel = max(cgImage.bitsPerPixel / 8, 0)
|
|
1090
|
+
let bytesPerRow = cgImage.bytesPerRow
|
|
1091
|
+
let width = cgImage.width
|
|
1092
|
+
let height = cgImage.height
|
|
1093
|
+
guard let bytes, bytesPerPixel >= 4, width > 0, height > 0 else {
|
|
1094
|
+
return image
|
|
654
1095
|
}
|
|
655
1096
|
|
|
656
|
-
|
|
657
|
-
|
|
1097
|
+
let alphaOffset: Int
|
|
1098
|
+
switch cgImage.alphaInfo {
|
|
1099
|
+
case .premultipliedLast, .last, .noneSkipLast:
|
|
1100
|
+
alphaOffset = 3
|
|
1101
|
+
case .premultipliedFirst, .first, .noneSkipFirst:
|
|
1102
|
+
alphaOffset = 0
|
|
1103
|
+
default:
|
|
1104
|
+
return image
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
var minX = width
|
|
1108
|
+
var minY = height
|
|
1109
|
+
var maxX = -1
|
|
1110
|
+
var maxY = -1
|
|
1111
|
+
let alphaThreshold: UInt8 = 8
|
|
1112
|
+
|
|
1113
|
+
for y in 0..<height {
|
|
1114
|
+
let rowStart = y * bytesPerRow
|
|
1115
|
+
for x in 0..<width {
|
|
1116
|
+
let pixelStart = rowStart + x * bytesPerPixel
|
|
1117
|
+
let alpha = bytes[pixelStart + alphaOffset]
|
|
1118
|
+
if alpha > alphaThreshold {
|
|
1119
|
+
minX = min(minX, x)
|
|
1120
|
+
minY = min(minY, y)
|
|
1121
|
+
maxX = max(maxX, x)
|
|
1122
|
+
maxY = max(maxY, y)
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
658
1125
|
}
|
|
659
1126
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
return kind == .background ? 255 : 255
|
|
1127
|
+
guard maxX >= minX, maxY >= minY else {
|
|
1128
|
+
return image
|
|
663
1129
|
}
|
|
664
1130
|
|
|
665
|
-
|
|
666
|
-
|
|
1131
|
+
let cropRect = CGRect(
|
|
1132
|
+
x: minX,
|
|
1133
|
+
y: minY,
|
|
1134
|
+
width: (maxX - minX + 1),
|
|
1135
|
+
height: (maxY - minY + 1)
|
|
1136
|
+
)
|
|
1137
|
+
guard let croppedCGImage = cgImage.cropping(to: cropRect) else {
|
|
1138
|
+
return image
|
|
667
1139
|
}
|
|
1140
|
+
return UIImage(cgImage: croppedCGImage, scale: image.scale, orientation: .up)
|
|
1141
|
+
}
|
|
668
1142
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
return
|
|
672
|
-
|
|
673
|
-
|
|
1143
|
+
private func aspectFitRect(sourceSize: CGSize, targetSize: CGSize) -> CGRect {
|
|
1144
|
+
guard sourceSize.width > 0, sourceSize.height > 0, targetSize.width > 0, targetSize.height > 0 else {
|
|
1145
|
+
return CGRect(origin: .zero, size: targetSize)
|
|
1146
|
+
}
|
|
1147
|
+
let scale = min(targetSize.width / sourceSize.width, targetSize.height / sourceSize.height)
|
|
1148
|
+
let drawSize = CGSize(width: sourceSize.width * scale, height: sourceSize.height * scale)
|
|
1149
|
+
return CGRect(
|
|
1150
|
+
x: (targetSize.width - drawSize.width) / 2.0,
|
|
1151
|
+
y: (targetSize.height - drawSize.height) / 2.0,
|
|
1152
|
+
width: drawSize.width,
|
|
1153
|
+
height: drawSize.height
|
|
1154
|
+
)
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
private func encodeTurnIconForLiveActivity(_ image: UIImage?) -> String? {
|
|
1158
|
+
guard let image else {
|
|
1159
|
+
return nil
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
let maxEncodedLength = 2600
|
|
1163
|
+
let targetSizes: [CGSize] = [
|
|
1164
|
+
CGSize(width: 34, height: 34),
|
|
1165
|
+
CGSize(width: 30, height: 30),
|
|
1166
|
+
CGSize(width: 26, height: 26),
|
|
1167
|
+
CGSize(width: 28, height: 28),
|
|
1168
|
+
CGSize(width: 24, height: 24),
|
|
1169
|
+
CGSize(width: 20, height: 20)
|
|
1170
|
+
]
|
|
1171
|
+
let preparedImage = trimmedTransparentBoundsImage(normalizedTurnIconImage(image))
|
|
1172
|
+
|
|
1173
|
+
for size in targetSizes {
|
|
1174
|
+
let renderer = UIGraphicsImageRenderer(size: size)
|
|
1175
|
+
let rendered = renderer.image { _ in
|
|
1176
|
+
let rect = aspectFitRect(sourceSize: preparedImage.size, targetSize: size)
|
|
1177
|
+
preparedImage.draw(in: rect)
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
if let pngData = rendered.pngData() {
|
|
1181
|
+
let pngBase64 = pngData.base64EncodedString()
|
|
1182
|
+
if pngBase64.count <= maxEncodedLength {
|
|
1183
|
+
return pngBase64
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
NSLog("[ExpoGaodeMapNaviView][LiveActivity] turn icon dropped because encoded payload is too large")
|
|
1189
|
+
return nil
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
private func fallbackTurnSymbolName(for iconType: Int) -> String {
|
|
1193
|
+
switch iconType {
|
|
1194
|
+
case 2:
|
|
1195
|
+
return "arrow.turn.up.left"
|
|
1196
|
+
case 3:
|
|
1197
|
+
return "arrow.turn.up.right"
|
|
1198
|
+
case 4:
|
|
1199
|
+
return "arrow.up.left"
|
|
1200
|
+
case 5:
|
|
1201
|
+
return "arrow.up.right"
|
|
1202
|
+
case 6:
|
|
1203
|
+
return "arrow.down.left"
|
|
1204
|
+
case 7:
|
|
1205
|
+
return "arrow.down.right"
|
|
1206
|
+
case 8:
|
|
1207
|
+
return "arrow.uturn.left"
|
|
1208
|
+
case 9, 20:
|
|
1209
|
+
return "arrow.up"
|
|
1210
|
+
case 11, 12:
|
|
1211
|
+
return "arrow.clockwise.circle"
|
|
1212
|
+
case 15:
|
|
1213
|
+
return "flag.checkered"
|
|
1214
|
+
case 19:
|
|
1215
|
+
return "arrow.uturn.right"
|
|
1216
|
+
case 65:
|
|
1217
|
+
return "arrow.left.circle"
|
|
1218
|
+
case 66:
|
|
1219
|
+
return "arrow.right.circle"
|
|
1220
|
+
default:
|
|
1221
|
+
return "arrow.up"
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
private func fallbackTurnIconImage(iconType: Int) -> UIImage? {
|
|
1226
|
+
let config = UIImage.SymbolConfiguration(pointSize: 36, weight: .bold)
|
|
1227
|
+
return UIImage(systemName: fallbackTurnSymbolName(for: iconType), withConfiguration: config)?
|
|
1228
|
+
.withTintColor(.white, renderingMode: .alwaysOriginal)
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
private func resolveTravelTurnIconImage(iconType: Int) -> UIImage? {
|
|
1232
|
+
let iconEnum = AMapNaviIconType(rawValue: iconType) ?? .none
|
|
1233
|
+
if activeScene == .ride {
|
|
1234
|
+
return AMapNaviRideView.rideViewTurnIconImage(with: iconEnum)
|
|
1235
|
+
}
|
|
1236
|
+
return fallbackTurnIconImage(iconType: iconType)
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
private func updateCachedTurnIconForTravelSceneIfNeeded(iconType: Int) {
|
|
1240
|
+
guard activeScene != .drive else {
|
|
1241
|
+
return
|
|
1242
|
+
}
|
|
1243
|
+
let image = resolveTravelTurnIconImage(iconType: iconType)
|
|
1244
|
+
if let encoded = encodeTurnIconForLiveActivity(image) {
|
|
1245
|
+
lastTurnIconBase64 = encoded
|
|
1246
|
+
}
|
|
1247
|
+
lastTurnIconImageUri = cacheTurnIconImage(
|
|
1248
|
+
image,
|
|
1249
|
+
prefix: "travel_turn_icon",
|
|
1250
|
+
previousUri: lastTurnIconImageUri
|
|
1251
|
+
)
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
private func cacheTurnIconImage(_ image: UIImage?, prefix: String, previousUri: String?) -> String? {
|
|
1255
|
+
guard let image, let data = image.pngData() else {
|
|
1256
|
+
if let previousUri {
|
|
1257
|
+
deleteCachedTurnIcon(at: previousUri)
|
|
1258
|
+
}
|
|
1259
|
+
return nil
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
let filename = "\(prefix)_\(UUID().uuidString).png"
|
|
1263
|
+
let fileURL = FileManager.default.temporaryDirectory.appendingPathComponent(filename)
|
|
1264
|
+
|
|
1265
|
+
do {
|
|
1266
|
+
try data.write(to: fileURL, options: .atomic)
|
|
1267
|
+
if let previousUri, previousUri != fileURL.absoluteString {
|
|
1268
|
+
deleteCachedTurnIcon(at: previousUri)
|
|
1269
|
+
}
|
|
1270
|
+
return fileURL.absoluteString
|
|
1271
|
+
} catch {
|
|
1272
|
+
return previousUri
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
private func deleteCachedTurnIcon(at uriString: String) {
|
|
1277
|
+
guard let fileURL = URL(string: uriString), fileURL.isFileURL else {
|
|
1278
|
+
return
|
|
1279
|
+
}
|
|
1280
|
+
try? FileManager.default.removeItem(at: fileURL)
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
private func clearCachedTurnIconUris() {
|
|
1284
|
+
if let lastTurnIconImageUri {
|
|
1285
|
+
deleteCachedTurnIcon(at: lastTurnIconImageUri)
|
|
1286
|
+
}
|
|
1287
|
+
if let lastNextTurnIconImageUri {
|
|
1288
|
+
deleteCachedTurnIcon(at: lastNextTurnIconImageUri)
|
|
1289
|
+
}
|
|
1290
|
+
lastTurnIconImageUri = nil
|
|
1291
|
+
lastNextTurnIconImageUri = nil
|
|
1292
|
+
lastTurnIconBase64 = nil
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
private func splitLaneInfoString(_ value: String) -> [String] {
|
|
1296
|
+
value
|
|
1297
|
+
.split(separator: "|", omittingEmptySubsequences: false)
|
|
1298
|
+
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() }
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
private func parseLaneToken(_ token: String, kind: LaneStringKind) -> Int? {
|
|
1302
|
+
guard !token.isEmpty else {
|
|
1303
|
+
return nil
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
if token == "255" || token == "ff" {
|
|
1307
|
+
return 255
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// Older iOS callbacks may use `f` as filler / unavailable lane marker.
|
|
1311
|
+
if token == "f" {
|
|
1312
|
+
return kind == .background ? 255 : 255
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
if let decimalValue = Int(token) {
|
|
1316
|
+
return decimalValue
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
switch token {
|
|
1320
|
+
case "a":
|
|
1321
|
+
return 10
|
|
1322
|
+
case "b":
|
|
1323
|
+
return 11
|
|
674
1324
|
case "c":
|
|
675
1325
|
return 12
|
|
676
1326
|
case "d":
|
|
@@ -732,39 +1382,90 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
732
1382
|
}
|
|
733
1383
|
|
|
734
1384
|
private func applyViewOptions() {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
1385
|
+
switch activeScene {
|
|
1386
|
+
case .drive:
|
|
1387
|
+
applyDriveViewOptions()
|
|
1388
|
+
case .walk:
|
|
1389
|
+
applyWalkViewOptions()
|
|
1390
|
+
case .ride:
|
|
1391
|
+
applyRideViewOptions()
|
|
1392
|
+
}
|
|
1393
|
+
applyCustomAnnotationImages()
|
|
1394
|
+
applyCustomUILayoutOptionsIfNeeded()
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
private func applyDriveViewOptions() {
|
|
1398
|
+
guard let driveView else {
|
|
1399
|
+
return
|
|
1400
|
+
}
|
|
1401
|
+
(driveView as? ExpoGaodeMapCustomDriveView)?.suppressBottomRightUI = showUIElements == false
|
|
1402
|
+
driveView.showUIElements = pendingShowUIElements ?? showUIElements
|
|
1403
|
+
driveView.showCamera = showCamera
|
|
1404
|
+
driveView.autoSwitchShowModeToCarPositionLocked = autoLockCar
|
|
1405
|
+
driveView.autoZoomMapLevel = autoChangeZoom
|
|
1406
|
+
driveView.mapShowTraffic = trafficLayerEnabled
|
|
1407
|
+
driveView.showCrossImage = realCrossDisplay
|
|
1408
|
+
driveView.showRoute = showRoute
|
|
1409
|
+
driveView.showTrafficBar = showTrafficBar
|
|
1410
|
+
driveView.showTrafficButton = showTrafficButton
|
|
1411
|
+
driveView.showBackupRoute = showBackupRoute
|
|
1412
|
+
driveView.showEagleMap = showEagleMap
|
|
1413
|
+
driveView.showVectorline = showVectorline
|
|
1414
|
+
driveView.showTrafficLights = showTrafficLights
|
|
1415
|
+
driveView.showDriveCongestion = showDriveCongestion
|
|
1416
|
+
driveView.showTrafficLightView = showTrafficLightView
|
|
1417
|
+
applyNaviMode(naviMode)
|
|
1418
|
+
applyShowMode(showMode)
|
|
1419
|
+
applyShowTurnArrow(showTurnArrow)
|
|
1420
|
+
applyShowBrowseRouteButton(showBrowseRouteButton)
|
|
1421
|
+
applyShowMoreButton(showMoreButton)
|
|
1422
|
+
applyShowGreyAfterPass(showGreyAfterPass)
|
|
1423
|
+
if let showCompassEnabled {
|
|
1424
|
+
applyShowCompassEnabled(showCompassEnabled)
|
|
1425
|
+
}
|
|
1426
|
+
applyLineWidth(lineWidth)
|
|
1427
|
+
applyScreenAnchor(screenAnchor)
|
|
1428
|
+
applyMapViewModeType(mapViewModeType)
|
|
748
1429
|
applyTrafficBarFrame(trafficBarFrame)
|
|
749
1430
|
applyTrafficBarColors(trafficBarColors)
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
private func applyWalkViewOptions() {
|
|
1434
|
+
guard let walkView else {
|
|
1435
|
+
return
|
|
1436
|
+
}
|
|
1437
|
+
walkView.showUIElements = pendingShowUIElements ?? showUIElements
|
|
1438
|
+
applyNaviMode(naviMode)
|
|
1439
|
+
applyShowMode(showMode)
|
|
1440
|
+
applyShowTurnArrow(showTurnArrow)
|
|
1441
|
+
applyShowBrowseRouteButton(showBrowseRouteButton)
|
|
1442
|
+
applyShowMoreButton(showMoreButton)
|
|
1443
|
+
applyShowGreyAfterPass(showGreyAfterPass)
|
|
758
1444
|
if let showCompassEnabled {
|
|
759
|
-
|
|
1445
|
+
applyShowCompassEnabled(showCompassEnabled)
|
|
1446
|
+
}
|
|
1447
|
+
applyLineWidth(lineWidth)
|
|
1448
|
+
applyScreenAnchor(screenAnchor)
|
|
1449
|
+
applyMapViewModeType(mapViewModeType)
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
private func applyRideViewOptions() {
|
|
1453
|
+
guard let rideView else {
|
|
1454
|
+
return
|
|
760
1455
|
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
1456
|
+
rideView.showUIElements = pendingShowUIElements ?? showUIElements
|
|
1457
|
+
applyNaviMode(naviMode)
|
|
1458
|
+
applyShowMode(showMode)
|
|
1459
|
+
applyShowTurnArrow(showTurnArrow)
|
|
1460
|
+
applyShowBrowseRouteButton(showBrowseRouteButton)
|
|
1461
|
+
applyShowMoreButton(showMoreButton)
|
|
1462
|
+
applyShowGreyAfterPass(showGreyAfterPass)
|
|
1463
|
+
if let showCompassEnabled {
|
|
1464
|
+
applyShowCompassEnabled(showCompassEnabled)
|
|
765
1465
|
}
|
|
766
|
-
|
|
767
|
-
|
|
1466
|
+
applyLineWidth(lineWidth)
|
|
1467
|
+
applyScreenAnchor(screenAnchor)
|
|
1468
|
+
applyMapViewModeType(mapViewModeType)
|
|
768
1469
|
}
|
|
769
1470
|
|
|
770
1471
|
private func applyCustomAnnotationImages() {
|
|
@@ -776,6 +1477,100 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
776
1477
|
applyCameraImageSource()
|
|
777
1478
|
}
|
|
778
1479
|
|
|
1480
|
+
private func applyCustomWaypointMarkerPayloads(_ payloads: [[String: Any]]?) {
|
|
1481
|
+
customWaypointMarkers = (payloads ?? []).compactMap { item in
|
|
1482
|
+
guard
|
|
1483
|
+
let latitude = item["latitude"] as? Double,
|
|
1484
|
+
let longitude = item["longitude"] as? Double
|
|
1485
|
+
else {
|
|
1486
|
+
return nil
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
let title = (item["title"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
1490
|
+
return NaviCustomWaypointMarkerModel(
|
|
1491
|
+
latitude: latitude,
|
|
1492
|
+
longitude: longitude,
|
|
1493
|
+
title: (title?.isEmpty == false ? title : nil) ?? "途经"
|
|
1494
|
+
)
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
refreshCustomWaypointAnnotations()
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
private func clearCustomWaypointAnnotations() {
|
|
1501
|
+
guard let driveView else {
|
|
1502
|
+
renderedCustomWaypointAnnotations.removeAll()
|
|
1503
|
+
return
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
for annotation in renderedCustomWaypointAnnotations {
|
|
1507
|
+
driveView.remove(annotation)
|
|
1508
|
+
}
|
|
1509
|
+
renderedCustomWaypointAnnotations.removeAll()
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
private func refreshCustomWaypointAnnotations() {
|
|
1513
|
+
clearCustomWaypointAnnotations()
|
|
1514
|
+
|
|
1515
|
+
guard activeScene == .drive, let driveView else {
|
|
1516
|
+
return
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
renderedCustomWaypointAnnotations = customWaypointMarkers.compactMap { marker in
|
|
1520
|
+
guard !marker.arrived else {
|
|
1521
|
+
return nil
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
let coordinate = CLLocationCoordinate2D(
|
|
1525
|
+
latitude: marker.latitude,
|
|
1526
|
+
longitude: marker.longitude
|
|
1527
|
+
)
|
|
1528
|
+
let bubbleView = NaviCustomWaypointBubbleView(title: marker.title)
|
|
1529
|
+
guard let annotation = AMapNaviCompositeCustomAnnotation(
|
|
1530
|
+
coordinate: coordinate,
|
|
1531
|
+
view: bubbleView
|
|
1532
|
+
) else {
|
|
1533
|
+
return nil
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
driveView.add(annotation)
|
|
1537
|
+
return annotation
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
private func resetCustomWaypointArrivalState() {
|
|
1542
|
+
customWaypointMarkers = customWaypointMarkers.map { marker in
|
|
1543
|
+
var nextMarker = marker
|
|
1544
|
+
nextMarker.arrived = false
|
|
1545
|
+
return nextMarker
|
|
1546
|
+
}
|
|
1547
|
+
refreshCustomWaypointAnnotations()
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
private func markNearestCustomWaypointArrived(_ point: AMapNaviPoint) {
|
|
1551
|
+
guard !customWaypointMarkers.isEmpty else {
|
|
1552
|
+
return
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
let targetLatitude = Double(point.latitude)
|
|
1556
|
+
let targetLongitude = Double(point.longitude)
|
|
1557
|
+
let nextIndex = customWaypointMarkers.enumerated()
|
|
1558
|
+
.filter { !$0.element.arrived }
|
|
1559
|
+
.min { lhs, rhs in
|
|
1560
|
+
let lhsDistance = abs(lhs.element.latitude - targetLatitude) + abs(lhs.element.longitude - targetLongitude)
|
|
1561
|
+
let rhsDistance = abs(rhs.element.latitude - targetLatitude) + abs(rhs.element.longitude - targetLongitude)
|
|
1562
|
+
return lhsDistance < rhsDistance
|
|
1563
|
+
}?
|
|
1564
|
+
.offset
|
|
1565
|
+
|
|
1566
|
+
guard let nextIndex else {
|
|
1567
|
+
return
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
customWaypointMarkers[nextIndex].arrived = true
|
|
1571
|
+
refreshCustomWaypointAnnotations()
|
|
1572
|
+
}
|
|
1573
|
+
|
|
779
1574
|
private func resolveLocalImage(_ source: String) -> UIImage? {
|
|
780
1575
|
if source.hasPrefix("file://") {
|
|
781
1576
|
let path = String(source.dropFirst(7))
|
|
@@ -818,58 +1613,76 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
818
1613
|
apply(resolveLocalImage(source))
|
|
819
1614
|
}
|
|
820
1615
|
|
|
821
|
-
private func
|
|
822
|
-
guard let
|
|
823
|
-
return
|
|
1616
|
+
private func resizeImageIfNeeded(_ image: UIImage?, targetSize: CGSize?) -> UIImage? {
|
|
1617
|
+
guard let image else {
|
|
1618
|
+
return nil
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
guard let targetSize, targetSize.width > 0, targetSize.height > 0 else {
|
|
1622
|
+
return image
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
let renderer = UIGraphicsImageRenderer(size: targetSize)
|
|
1626
|
+
return renderer.image { _ in
|
|
1627
|
+
image.draw(in: CGRect(origin: .zero, size: targetSize))
|
|
824
1628
|
}
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
private func applyCarImageSource() {
|
|
825
1632
|
applyAnnotationImage(source: carImageSource, currentSource: { [weak self] in
|
|
826
1633
|
self?.carImageSource
|
|
827
|
-
}) { [weak driveView] image in
|
|
828
|
-
|
|
1634
|
+
}) { [weak self, weak driveView, weak walkView, weak rideView] image in
|
|
1635
|
+
let resizedImage = self?.resizeImageIfNeeded(image, targetSize: self?.carImageSize) ?? image
|
|
1636
|
+
driveView?.setCarImage(resizedImage)
|
|
1637
|
+
walkView?.setCarImage(resizedImage)
|
|
1638
|
+
if let resizedImage {
|
|
1639
|
+
rideView?.setCarImageWithSize(resizedImage)
|
|
1640
|
+
} else {
|
|
1641
|
+
rideView?.setCarImage(nil)
|
|
1642
|
+
}
|
|
829
1643
|
}
|
|
830
1644
|
}
|
|
831
1645
|
|
|
832
1646
|
private func applyCarCompassImageSource() {
|
|
833
|
-
guard let driveView else {
|
|
834
|
-
return
|
|
835
|
-
}
|
|
836
1647
|
applyAnnotationImage(source: carCompassImageSource, currentSource: { [weak self] in
|
|
837
1648
|
self?.carCompassImageSource
|
|
838
|
-
}) { [weak driveView] image in
|
|
1649
|
+
}) { [weak driveView, weak walkView, weak rideView] image in
|
|
839
1650
|
driveView?.setCarCompassImage(image)
|
|
1651
|
+
walkView?.setCarCompassImage(image)
|
|
1652
|
+
rideView?.setCarCompassImage(image)
|
|
840
1653
|
}
|
|
841
1654
|
}
|
|
842
1655
|
|
|
843
1656
|
private func applyStartPointImageSource() {
|
|
844
|
-
guard let driveView else {
|
|
845
|
-
return
|
|
846
|
-
}
|
|
847
1657
|
applyAnnotationImage(source: startPointImageSource, currentSource: { [weak self] in
|
|
848
1658
|
self?.startPointImageSource
|
|
849
|
-
}) { [weak driveView] image in
|
|
1659
|
+
}) { [weak driveView, weak walkView, weak rideView] image in
|
|
850
1660
|
driveView?.setStartPointImage(image)
|
|
1661
|
+
walkView?.setStartPointImage(image)
|
|
1662
|
+
rideView?.setStartPointImage(image)
|
|
851
1663
|
}
|
|
852
1664
|
}
|
|
853
1665
|
|
|
854
1666
|
private func applyWayPointImageSource() {
|
|
855
|
-
guard let
|
|
1667
|
+
guard let source = wayPointImageSource?.trimmingCharacters(in: .whitespacesAndNewlines), !source.isEmpty else {
|
|
856
1668
|
return
|
|
857
1669
|
}
|
|
858
1670
|
applyAnnotationImage(source: wayPointImageSource, currentSource: { [weak self] in
|
|
859
1671
|
self?.wayPointImageSource
|
|
860
|
-
}) { [weak driveView] image in
|
|
1672
|
+
}) { [weak driveView, weak walkView, weak rideView] image in
|
|
861
1673
|
driveView?.setWayPointImage(image)
|
|
1674
|
+
walkView?.setWayPointImage(image)
|
|
1675
|
+
rideView?.setWayPointImage(image)
|
|
862
1676
|
}
|
|
863
1677
|
}
|
|
864
1678
|
|
|
865
1679
|
private func applyEndPointImageSource() {
|
|
866
|
-
guard let driveView else {
|
|
867
|
-
return
|
|
868
|
-
}
|
|
869
1680
|
applyAnnotationImage(source: endPointImageSource, currentSource: { [weak self] in
|
|
870
1681
|
self?.endPointImageSource
|
|
871
|
-
}) { [weak driveView] image in
|
|
1682
|
+
}) { [weak driveView, weak walkView, weak rideView] image in
|
|
872
1683
|
driveView?.setEndPointImage(image)
|
|
1684
|
+
walkView?.setEndPointImage(image)
|
|
1685
|
+
rideView?.setEndPointImage(image)
|
|
873
1686
|
}
|
|
874
1687
|
}
|
|
875
1688
|
|
|
@@ -884,54 +1697,93 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
884
1697
|
}
|
|
885
1698
|
}
|
|
886
1699
|
|
|
887
|
-
private func
|
|
888
|
-
guard
|
|
1700
|
+
private func applyShowUIElementsToActiveViewIfReady() {
|
|
1701
|
+
guard currentNaviView() != nil else {
|
|
889
1702
|
pendingShowUIElements = showUIElements
|
|
890
1703
|
return
|
|
891
1704
|
}
|
|
892
1705
|
let value = pendingShowUIElements ?? showUIElements
|
|
893
1706
|
pendingShowUIElements = nil
|
|
894
|
-
|
|
1707
|
+
|
|
1708
|
+
switch activeScene {
|
|
1709
|
+
case .drive:
|
|
1710
|
+
(driveView as? ExpoGaodeMapCustomDriveView)?.suppressBottomRightUI = value == false
|
|
1711
|
+
driveView?.showUIElements = value
|
|
1712
|
+
case .walk:
|
|
1713
|
+
walkView?.showUIElements = value
|
|
1714
|
+
case .ride:
|
|
1715
|
+
rideView?.showUIElements = value
|
|
1716
|
+
}
|
|
1717
|
+
|
|
895
1718
|
applyCustomUILayoutOptionsIfNeeded()
|
|
896
1719
|
}
|
|
897
1720
|
|
|
898
1721
|
private func applyCustomUILayoutOptionsIfNeeded() {
|
|
899
|
-
guard
|
|
1722
|
+
guard showUIElements == false else {
|
|
1723
|
+
(driveView as? ExpoGaodeMapCustomDriveView)?.suppressBottomRightUI = false
|
|
900
1724
|
return
|
|
901
1725
|
}
|
|
902
1726
|
|
|
903
|
-
|
|
904
|
-
|
|
1727
|
+
switch activeScene {
|
|
1728
|
+
case .drive:
|
|
1729
|
+
guard let driveView else {
|
|
1730
|
+
return
|
|
1731
|
+
}
|
|
1732
|
+
(driveView as? ExpoGaodeMapCustomDriveView)?.suppressBottomRightUI = true
|
|
1733
|
+
driveView.showCrossImage = realCrossDisplay
|
|
1734
|
+
driveView.showTrafficBar = showTrafficBar
|
|
1735
|
+
applyTrafficBarFrame(trafficBarFrame)
|
|
1736
|
+
applyTrafficBarColors(trafficBarColors)
|
|
1737
|
+
driveView.screenAnchor = screenAnchor
|
|
1738
|
+
driveView.setNeedsLayout()
|
|
1739
|
+
driveView.layoutIfNeeded()
|
|
1740
|
+
case .walk:
|
|
1741
|
+
guard let walkView else {
|
|
1742
|
+
return
|
|
1743
|
+
}
|
|
1744
|
+
walkView.screenAnchor = screenAnchor
|
|
1745
|
+
walkView.setNeedsLayout()
|
|
1746
|
+
walkView.layoutIfNeeded()
|
|
1747
|
+
case .ride:
|
|
1748
|
+
guard let rideView else {
|
|
1749
|
+
return
|
|
1750
|
+
}
|
|
1751
|
+
rideView.screenAnchor = screenAnchor
|
|
1752
|
+
rideView.setNeedsLayout()
|
|
1753
|
+
rideView.layoutIfNeeded()
|
|
905
1754
|
}
|
|
906
1755
|
|
|
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
1756
|
scheduleOverviewRouteVisibleRegionRefresh()
|
|
917
1757
|
}
|
|
918
1758
|
|
|
919
1759
|
private func refreshOverviewRouteVisibleRegionIfNeeded() {
|
|
920
|
-
guard showUIElements == false
|
|
1760
|
+
guard showUIElements == false else {
|
|
921
1761
|
return
|
|
922
1762
|
}
|
|
923
1763
|
|
|
924
|
-
|
|
925
|
-
|
|
1764
|
+
switch activeScene {
|
|
1765
|
+
case .drive:
|
|
1766
|
+
guard let driveView, driveView.showMode == .overview else {
|
|
1767
|
+
return
|
|
1768
|
+
}
|
|
1769
|
+
driveView.updateRoutePolylineInTheVisualRangeWhenTheShowModeIsOverview()
|
|
1770
|
+
case .walk:
|
|
1771
|
+
guard let walkView, walkView.showMode == .overview else {
|
|
1772
|
+
return
|
|
1773
|
+
}
|
|
1774
|
+
walkView.updateRoutePolylineInTheVisualRangeWhenTheShowModeIsOverview()
|
|
1775
|
+
case .ride:
|
|
1776
|
+
guard let rideView, rideView.showMode == .overview else {
|
|
1777
|
+
return
|
|
1778
|
+
}
|
|
1779
|
+
rideView.updateRoutePolylineInTheVisualRangeWhenTheShowModeIsOverview()
|
|
926
1780
|
}
|
|
927
|
-
|
|
928
|
-
driveView.updateRoutePolylineInTheVisualRangeWhenTheShowModeIsOverview()
|
|
929
1781
|
}
|
|
930
1782
|
|
|
931
1783
|
private func scheduleOverviewRouteVisibleRegionRefresh() {
|
|
932
1784
|
DispatchQueue.main.async { [weak self] in
|
|
933
|
-
self?.
|
|
934
|
-
self?.
|
|
1785
|
+
self?.currentNaviView()?.setNeedsLayout()
|
|
1786
|
+
self?.currentNaviView()?.layoutIfNeeded()
|
|
935
1787
|
self?.refreshOverviewRouteVisibleRegionIfNeeded()
|
|
936
1788
|
}
|
|
937
1789
|
}
|
|
@@ -951,7 +1803,8 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
951
1803
|
return
|
|
952
1804
|
}
|
|
953
1805
|
|
|
954
|
-
guard frame.width > 0, frame.height > 0 else {
|
|
1806
|
+
guard showTrafficBar, frame.width > 0, frame.height > 0 else {
|
|
1807
|
+
driveView.tmcRouteFrame = .zero
|
|
955
1808
|
return
|
|
956
1809
|
}
|
|
957
1810
|
|
|
@@ -991,6 +1844,20 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
991
1844
|
}
|
|
992
1845
|
|
|
993
1846
|
private func emitTrafficStatusesUpdate(_ trafficStatuses: [AMapNaviTrafficStatus]?) {
|
|
1847
|
+
let totalLengthFromTraffic = (trafficStatuses ?? []).reduce(0) { partial, status in
|
|
1848
|
+
partial + max(status.length, 0)
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
if totalLengthFromTraffic > 0 {
|
|
1852
|
+
if let retainDistance = lastNavigationInfoPayload?["pathRetainDistance"] as? Int {
|
|
1853
|
+
if totalLengthFromTraffic >= retainDistance {
|
|
1854
|
+
trafficBarTotalLength = totalLengthFromTraffic
|
|
1855
|
+
}
|
|
1856
|
+
} else {
|
|
1857
|
+
trafficBarTotalLength = totalLengthFromTraffic
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
|
|
994
1861
|
// iOS 会提供 fineStatus;统一事件结构时保留它,方便 RN 自绘层按需细化颜色策略。
|
|
995
1862
|
let items = (trafficStatuses ?? []).map { status in
|
|
996
1863
|
var payload: [String: Any] = [
|
|
@@ -1005,7 +1872,12 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
1005
1872
|
"items": items
|
|
1006
1873
|
]
|
|
1007
1874
|
|
|
1008
|
-
|
|
1875
|
+
let resolvedTotalLength = max(trafficBarTotalLength ?? 0, currentRouteTotalLength ?? 0)
|
|
1876
|
+
if resolvedTotalLength > 0 {
|
|
1877
|
+
payload["totalLength"] = resolvedTotalLength
|
|
1878
|
+
} else if totalLengthFromTraffic > 0 {
|
|
1879
|
+
payload["totalLength"] = totalLengthFromTraffic
|
|
1880
|
+
} else if let totalLength = currentRouteTotalLength, totalLength > 0 {
|
|
1009
1881
|
payload["totalLength"] = totalLength
|
|
1010
1882
|
}
|
|
1011
1883
|
|
|
@@ -1023,6 +1895,13 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
1023
1895
|
|
|
1024
1896
|
private func applyEnableVoice(_ enabled: Bool) {
|
|
1025
1897
|
driveManager?.isUseInternalTTS = enabled
|
|
1898
|
+
walkManager?.isUseInternalTTS = enabled
|
|
1899
|
+
rideManager?.isUseInternalTTS = enabled
|
|
1900
|
+
if enabled {
|
|
1901
|
+
activateNavigationAudioSessionIfNeeded(reason: "enable_voice_true")
|
|
1902
|
+
} else {
|
|
1903
|
+
deactivateNavigationAudioSessionIfNeeded(reason: "enable_voice_false")
|
|
1904
|
+
}
|
|
1026
1905
|
// 内置语音会自动播报,不需要手动调用 startSpeak/stopSpeak
|
|
1027
1906
|
}
|
|
1028
1907
|
|
|
@@ -1043,43 +1922,260 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
1043
1922
|
}
|
|
1044
1923
|
|
|
1045
1924
|
private func applyNaviMode(_ mode: Int) {
|
|
1046
|
-
|
|
1925
|
+
let trackingMode: AMapNaviViewTrackingMode = mode == 0 ? .carNorth : .mapNorth
|
|
1926
|
+
switch activeScene {
|
|
1927
|
+
case .drive:
|
|
1928
|
+
driveView?.trackingMode = trackingMode
|
|
1929
|
+
case .walk:
|
|
1930
|
+
walkView?.trackingMode = trackingMode
|
|
1931
|
+
case .ride:
|
|
1932
|
+
rideView?.trackingMode = trackingMode
|
|
1933
|
+
}
|
|
1047
1934
|
}
|
|
1048
1935
|
|
|
1049
1936
|
private func applyShowMode(_ mode: Int) {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1937
|
+
switch activeScene {
|
|
1938
|
+
case .drive:
|
|
1939
|
+
switch mode {
|
|
1940
|
+
case 1:
|
|
1941
|
+
driveView?.showMode = .carPositionLocked
|
|
1942
|
+
case 2:
|
|
1943
|
+
driveView?.showMode = .overview
|
|
1944
|
+
case 3:
|
|
1945
|
+
driveView?.showMode = .normal
|
|
1946
|
+
default:
|
|
1947
|
+
break
|
|
1948
|
+
}
|
|
1949
|
+
case .walk:
|
|
1950
|
+
switch mode {
|
|
1951
|
+
case 1:
|
|
1952
|
+
walkView?.showMode = .carPositionLocked
|
|
1953
|
+
case 2:
|
|
1954
|
+
walkView?.showMode = .overview
|
|
1955
|
+
case 3:
|
|
1956
|
+
walkView?.showMode = .normal
|
|
1957
|
+
default:
|
|
1958
|
+
break
|
|
1959
|
+
}
|
|
1960
|
+
case .ride:
|
|
1961
|
+
switch mode {
|
|
1962
|
+
case 1:
|
|
1963
|
+
rideView?.showMode = .carPositionLocked
|
|
1964
|
+
case 2:
|
|
1965
|
+
rideView?.showMode = .overview
|
|
1966
|
+
case 3:
|
|
1967
|
+
rideView?.showMode = .normal
|
|
1968
|
+
default:
|
|
1969
|
+
break
|
|
1970
|
+
}
|
|
1060
1971
|
}
|
|
1061
1972
|
scheduleOverviewRouteVisibleRegionRefresh()
|
|
1062
1973
|
}
|
|
1063
1974
|
|
|
1064
1975
|
private func applyNightMode(_ enabled: Bool) {
|
|
1065
|
-
|
|
1976
|
+
applyMapViewModeType(enabled ? 1 : 0)
|
|
1066
1977
|
}
|
|
1067
1978
|
|
|
1068
1979
|
private func applyMapViewModeType(_ type: Int) {
|
|
1069
|
-
|
|
1980
|
+
let resolvedMode: AMapNaviViewMapModeType
|
|
1070
1981
|
switch type {
|
|
1071
1982
|
case 0:
|
|
1072
|
-
|
|
1983
|
+
resolvedMode = .day
|
|
1073
1984
|
case 1:
|
|
1074
|
-
|
|
1985
|
+
resolvedMode = .night
|
|
1075
1986
|
case 2:
|
|
1076
|
-
|
|
1987
|
+
resolvedMode = .dayNightAuto
|
|
1077
1988
|
case 3:
|
|
1078
|
-
|
|
1989
|
+
resolvedMode = .custom
|
|
1079
1990
|
default:
|
|
1080
|
-
|
|
1991
|
+
return
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
switch activeScene {
|
|
1995
|
+
case .drive:
|
|
1996
|
+
driveView?.mapViewModeType = resolvedMode
|
|
1997
|
+
case .walk:
|
|
1998
|
+
walkView?.mapViewModeType = resolvedMode
|
|
1999
|
+
case .ride:
|
|
2000
|
+
rideView?.mapViewModeType = resolvedMode
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
private func applyShowTurnArrow(_ visible: Bool) {
|
|
2005
|
+
switch activeScene {
|
|
2006
|
+
case .drive:
|
|
2007
|
+
driveView?.showTurnArrow = visible
|
|
2008
|
+
case .walk:
|
|
2009
|
+
walkView?.showTurnArrow = visible
|
|
2010
|
+
case .ride:
|
|
2011
|
+
rideView?.showTurnArrow = visible
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
private func applyShowBrowseRouteButton(_ visible: Bool) {
|
|
2016
|
+
switch activeScene {
|
|
2017
|
+
case .drive:
|
|
2018
|
+
driveView?.showBrowseRouteButton = visible
|
|
2019
|
+
case .walk:
|
|
2020
|
+
walkView?.showBrowseRouteButton = visible
|
|
2021
|
+
case .ride:
|
|
2022
|
+
rideView?.showBrowseRouteButton = visible
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
private func applyShowMoreButton(_ visible: Bool) {
|
|
2027
|
+
switch activeScene {
|
|
2028
|
+
case .drive:
|
|
2029
|
+
driveView?.showMoreButton = visible
|
|
2030
|
+
case .walk:
|
|
2031
|
+
walkView?.showMoreButton = visible
|
|
2032
|
+
case .ride:
|
|
2033
|
+
rideView?.showMoreButton = visible
|
|
1081
2034
|
}
|
|
1082
2035
|
}
|
|
2036
|
+
|
|
2037
|
+
private func applyShowGreyAfterPass(_ enabled: Bool) {
|
|
2038
|
+
switch activeScene {
|
|
2039
|
+
case .drive:
|
|
2040
|
+
driveView?.showGreyAfterPass = enabled
|
|
2041
|
+
case .walk:
|
|
2042
|
+
walkView?.showGreyAfterPass = enabled
|
|
2043
|
+
case .ride:
|
|
2044
|
+
rideView?.showGreyAfterPass = enabled
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
private func applyShowCompassEnabled(_ enabled: Bool) {
|
|
2049
|
+
switch activeScene {
|
|
2050
|
+
case .drive:
|
|
2051
|
+
driveView?.showCompass = enabled
|
|
2052
|
+
case .walk:
|
|
2053
|
+
walkView?.showCompass = enabled
|
|
2054
|
+
case .ride:
|
|
2055
|
+
rideView?.showCompass = enabled
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
private func applyLineWidth(_ width: CGFloat) {
|
|
2060
|
+
switch activeScene {
|
|
2061
|
+
case .drive:
|
|
2062
|
+
driveView?.lineWidth = width
|
|
2063
|
+
case .walk:
|
|
2064
|
+
walkView?.lineWidth = width
|
|
2065
|
+
case .ride:
|
|
2066
|
+
rideView?.lineWidth = width
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
private func applyScreenAnchor(_ anchor: CGPoint) {
|
|
2071
|
+
switch activeScene {
|
|
2072
|
+
case .drive:
|
|
2073
|
+
driveView?.screenAnchor = anchor
|
|
2074
|
+
case .walk:
|
|
2075
|
+
walkView?.screenAnchor = anchor
|
|
2076
|
+
case .ride:
|
|
2077
|
+
rideView?.screenAnchor = anchor
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
private func applyBackgroundLocationOptionsForActiveScene() {
|
|
2082
|
+
switch activeScene {
|
|
2083
|
+
case .drive:
|
|
2084
|
+
applyDriveManagerBackgroundLocationOptionsIfNeeded()
|
|
2085
|
+
case .walk:
|
|
2086
|
+
applyWalkManagerBackgroundLocationOptionsIfNeeded()
|
|
2087
|
+
case .ride:
|
|
2088
|
+
applyRideManagerBackgroundLocationOptionsIfNeeded()
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
private func handleNavigationStarted(_ naviMode: AMapNaviMode) {
|
|
2093
|
+
hasStartedNavi = true
|
|
2094
|
+
applyBackgroundLocationOptionsForActiveScene()
|
|
2095
|
+
activateNavigationAudioSessionIfNeeded(reason: "did_start_navi")
|
|
2096
|
+
onNavigationStarted([
|
|
2097
|
+
"type": naviMode == .emulator ? 1 : 0,
|
|
2098
|
+
"isEmulator": naviMode == .emulator
|
|
2099
|
+
])
|
|
2100
|
+
applyShowUIElementsToActiveViewIfReady()
|
|
2101
|
+
refreshCustomWaypointAnnotations()
|
|
2102
|
+
syncNavigationLiveActivityWithLastPayload()
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
private func handleNavigationLocationUpdate(_ naviLocation: AMapNaviLocation) {
|
|
2106
|
+
if !hasReceivedFirstNaviData {
|
|
2107
|
+
hasReceivedFirstNaviData = true
|
|
2108
|
+
applyShowUIElementsToActiveViewIfReady()
|
|
2109
|
+
}
|
|
2110
|
+
lastKnownSpeed = Int(naviLocation.speed)
|
|
2111
|
+
onLocationUpdate([
|
|
2112
|
+
"latitude": naviLocation.coordinate.latitude,
|
|
2113
|
+
"longitude": naviLocation.coordinate.longitude,
|
|
2114
|
+
"speed": naviLocation.speed,
|
|
2115
|
+
"bearing": naviLocation.heading
|
|
2116
|
+
])
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
private func navigationInfoPayload(from naviInfo: AMapNaviInfo) -> [String: Any] {
|
|
2120
|
+
[
|
|
2121
|
+
"naviMode": naviInfo.naviMode.rawValue,
|
|
2122
|
+
"currentRoadName": naviInfo.currentRoadName ?? "",
|
|
2123
|
+
"nextRoadName": naviInfo.nextRoadName ?? "",
|
|
2124
|
+
"pathRetainDistance": naviInfo.routeRemainDistance,
|
|
2125
|
+
"pathRetainTime": naviInfo.routeRemainTime,
|
|
2126
|
+
"curStepRetainDistance": naviInfo.segmentRemainDistance,
|
|
2127
|
+
"curStepRetainTime": naviInfo.segmentRemainTime,
|
|
2128
|
+
"currentSpeed": lastKnownSpeed,
|
|
2129
|
+
"iconType": naviInfo.iconType.rawValue,
|
|
2130
|
+
"iconDirection": naviInfo.iconType.rawValue,
|
|
2131
|
+
"currentSegmentIndex": naviInfo.currentSegmentIndex,
|
|
2132
|
+
"currentLinkIndex": naviInfo.currentLinkIndex,
|
|
2133
|
+
"currentPointIndex": naviInfo.currentPointIndex,
|
|
2134
|
+
"routeRemainTrafficLightCount": naviInfo.routeRemainTrafficLightCount,
|
|
2135
|
+
"driveDistance": naviInfo.routeDriveDistance,
|
|
2136
|
+
"driveTime": naviInfo.routeDriveTime
|
|
2137
|
+
]
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
private func handleNavigationInfoUpdate(_ naviInfo: AMapNaviInfo) {
|
|
2141
|
+
if !hasReceivedFirstNaviData {
|
|
2142
|
+
hasReceivedFirstNaviData = true
|
|
2143
|
+
applyShowUIElementsToActiveViewIfReady()
|
|
2144
|
+
}
|
|
2145
|
+
updateCachedTurnIconForTravelSceneIfNeeded(iconType: Int(naviInfo.iconType.rawValue))
|
|
2146
|
+
emitNavigationInfoUpdate(navigationInfoPayload(from: naviInfo))
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
private func handleNavigationSound(_ soundString: String, soundStringType: AMapNaviSoundType) {
|
|
2150
|
+
activateNavigationAudioSessionIfNeeded(reason: "play_navi_sound")
|
|
2151
|
+
onNavigationText([
|
|
2152
|
+
"type": soundStringType.rawValue,
|
|
2153
|
+
"text": soundString
|
|
2154
|
+
])
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
private func handleGpsSignalUpdate(_ gpsSignalStrength: AMapNaviGPSSignalStrength) {
|
|
2158
|
+
let rawValue = gpsSignalStrength.rawValue
|
|
2159
|
+
let isWeak = rawValue == AMapNaviGPSSignalStrength.weak.rawValue || rawValue == 0
|
|
2160
|
+
onGpsSignalWeak([
|
|
2161
|
+
"isWeak": isWeak
|
|
2162
|
+
])
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
private func handleWayPointArrived(index: Int, point: AMapNaviPoint? = nil) {
|
|
2166
|
+
if let point {
|
|
2167
|
+
markNearestCustomWaypointArrived(point)
|
|
2168
|
+
}
|
|
2169
|
+
onWayPointArrived([
|
|
2170
|
+
"index": index
|
|
2171
|
+
])
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
private func handleDidEndEmulatorNavi(reason: String) {
|
|
2175
|
+
resetTransientNavigationState()
|
|
2176
|
+
deactivateNavigationAudioSessionIfNeeded(reason: reason)
|
|
2177
|
+
onNavigationEnded([:])
|
|
2178
|
+
}
|
|
1083
2179
|
|
|
1084
2180
|
// MARK: - Public Methods
|
|
1085
2181
|
func startNavigation(startLat: Double, startLng: Double, endLat: Double, endLng: Double, promise: Promise) {
|
|
@@ -1101,8 +2197,8 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
1101
2197
|
promise.reject(code, formatError(error))
|
|
1102
2198
|
return
|
|
1103
2199
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
2200
|
+
|
|
2201
|
+
switchToScene(.drive)
|
|
1106
2202
|
resetTransientNavigationState()
|
|
1107
2203
|
|
|
1108
2204
|
startCoordinate = AMapNaviPoint.location(withLatitude: CGFloat(startLat), longitude: CGFloat(startLng))
|
|
@@ -1157,7 +2253,8 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
1157
2253
|
return
|
|
1158
2254
|
}
|
|
1159
2255
|
|
|
1160
|
-
|
|
2256
|
+
let scene = NaviScene(rawValue: independentRouteManager.scene(for: token) ?? "") ?? .drive
|
|
2257
|
+
switchToScene(scene)
|
|
1161
2258
|
resetTransientNavigationState()
|
|
1162
2259
|
|
|
1163
2260
|
if let naviType {
|
|
@@ -1184,7 +2281,14 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
1184
2281
|
}
|
|
1185
2282
|
|
|
1186
2283
|
func stopNavigation(promise: Promise) {
|
|
1187
|
-
|
|
2284
|
+
switch activeScene {
|
|
2285
|
+
case .drive:
|
|
2286
|
+
driveManager?.stopNavi()
|
|
2287
|
+
case .walk:
|
|
2288
|
+
walkManager?.stopNavi()
|
|
2289
|
+
case .ride:
|
|
2290
|
+
rideManager?.stopNavi()
|
|
2291
|
+
}
|
|
1188
2292
|
resetTransientNavigationState()
|
|
1189
2293
|
promise.resolve([
|
|
1190
2294
|
"success": true,
|
|
@@ -1193,35 +2297,81 @@ public class ExpoGaodeMapNaviView: ExpoView {
|
|
|
1193
2297
|
}
|
|
1194
2298
|
|
|
1195
2299
|
func playCustomTTS(text: String, forcePlay: Bool, promise: Promise) {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
2300
|
+
guard let manager = currentNaviManager() else {
|
|
2301
|
+
promise.reject("NAVI_MANAGER_UNAVAILABLE", "导航管理器尚未初始化")
|
|
2302
|
+
return
|
|
2303
|
+
}
|
|
2304
|
+
let success = manager.playTTS(text, forcePlay: forcePlay)
|
|
2305
|
+
if success {
|
|
2306
|
+
promise.resolve([
|
|
2307
|
+
"success": true
|
|
2308
|
+
])
|
|
2309
|
+
} else {
|
|
2310
|
+
promise.reject("PLAY_TTS_FAILED", "当前场景暂不支持或正在播报其他导航语音")
|
|
2311
|
+
}
|
|
1200
2312
|
}
|
|
1201
2313
|
|
|
1202
2314
|
// MARK: - Lifecycle
|
|
1203
2315
|
public override func layoutSubviews() {
|
|
1204
2316
|
super.layoutSubviews()
|
|
1205
2317
|
driveView?.frame = bounds
|
|
2318
|
+
walkView?.frame = bounds
|
|
2319
|
+
rideView?.frame = bounds
|
|
1206
2320
|
scheduleOverviewRouteVisibleRegionRefresh()
|
|
1207
2321
|
}
|
|
1208
2322
|
|
|
1209
2323
|
deinit {
|
|
2324
|
+
NavigationLiveActivityManager.shared.stop()
|
|
2325
|
+
deactivateNavigationAudioSessionIfNeeded(reason: "deinit")
|
|
1210
2326
|
driveManager?.stopNavi()
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
2327
|
+
walkManager?.stopNavi()
|
|
2328
|
+
rideManager?.stopNavi()
|
|
2329
|
+
clearCustomWaypointAnnotations()
|
|
2330
|
+
destroyDriveManagerIfNeeded()
|
|
2331
|
+
destroyWalkManagerIfNeeded()
|
|
2332
|
+
destroyRideManagerIfNeeded()
|
|
1216
2333
|
clearCachedTurnIconUris()
|
|
1217
2334
|
}
|
|
1218
2335
|
}
|
|
1219
2336
|
|
|
1220
2337
|
// MARK: - AMapNaviDriveManagerDelegate
|
|
1221
2338
|
extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
|
|
2339
|
+
private func makeArrivedLiveActivitySnapshot() -> NavigationLiveActivitySnapshot {
|
|
2340
|
+
let remainDistance = payloadIntValue(lastNavigationInfoPayload?["pathRetainDistance"]) ?? 0
|
|
2341
|
+
let routeTotalDistance = max(
|
|
2342
|
+
trafficBarTotalLength ?? 0,
|
|
2343
|
+
currentRouteTotalLength ?? 0,
|
|
2344
|
+
remainDistance
|
|
2345
|
+
)
|
|
2346
|
+
return NavigationLiveActivitySnapshot(
|
|
2347
|
+
appName: resolveAppDisplayName(),
|
|
2348
|
+
currentRoadName: "",
|
|
2349
|
+
nextRoadName: "",
|
|
2350
|
+
pathRetainDistance: 0,
|
|
2351
|
+
routeTotalDistance: routeTotalDistance,
|
|
2352
|
+
pathRetainTime: 0,
|
|
2353
|
+
curStepRetainDistance: 0,
|
|
2354
|
+
iconType: 15,
|
|
2355
|
+
turnIconBase64: nil
|
|
2356
|
+
)
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
private func handleArrivedDestination(source: String) {
|
|
2360
|
+
NSLog("[ExpoGaodeMapNaviView][LiveActivity] arrived destination callback received: %@", source)
|
|
2361
|
+
hasStartedNavi = false
|
|
2362
|
+
if iosLiveActivityEnabled {
|
|
2363
|
+
let arrivedSnapshot = makeArrivedLiveActivitySnapshot()
|
|
2364
|
+
NavigationLiveActivityManager.shared.showArrivedAndStop(snapshot: arrivedSnapshot, dismissAfter: 6)
|
|
2365
|
+
} else {
|
|
2366
|
+
NavigationLiveActivityManager.shared.stop()
|
|
2367
|
+
}
|
|
2368
|
+
onArriveDestination([:])
|
|
2369
|
+
}
|
|
1222
2370
|
|
|
1223
2371
|
public func driveManager(onCalculateRouteSuccess driveManager: AMapNaviDriveManager) {
|
|
1224
2372
|
hasStartedNavi = true
|
|
2373
|
+
applyDriveManagerBackgroundLocationOptionsIfNeeded()
|
|
2374
|
+
activateNavigationAudioSessionIfNeeded(reason: "calculate_route_success")
|
|
1225
2375
|
onRouteCalculated([
|
|
1226
2376
|
"success": true,
|
|
1227
2377
|
"naviType": naviType
|
|
@@ -1234,9 +2384,10 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
|
|
|
1234
2384
|
driveManager.startGPSNavi()
|
|
1235
2385
|
}
|
|
1236
2386
|
|
|
1237
|
-
|
|
2387
|
+
applyShowUIElementsToActiveViewIfReady()
|
|
1238
2388
|
DispatchQueue.main.async { [weak self] in
|
|
1239
2389
|
self?.applyCustomAnnotationImages()
|
|
2390
|
+
self?.refreshCustomWaypointAnnotations()
|
|
1240
2391
|
}
|
|
1241
2392
|
}
|
|
1242
2393
|
|
|
@@ -1248,54 +2399,47 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveManagerDelegate {
|
|
|
1248
2399
|
}
|
|
1249
2400
|
|
|
1250
2401
|
public func driveManager(_ driveManager: AMapNaviDriveManager, didStartNavi naviMode: AMapNaviMode) {
|
|
1251
|
-
|
|
1252
|
-
onNavigationStarted([
|
|
1253
|
-
"type": naviMode == .emulator ? 1 : 0,
|
|
1254
|
-
"isEmulator": naviMode == .emulator
|
|
1255
|
-
])
|
|
1256
|
-
|
|
1257
|
-
applyShowUIElementsToDriveViewIfReady()
|
|
2402
|
+
handleNavigationStarted(naviMode)
|
|
1258
2403
|
}
|
|
1259
2404
|
|
|
1260
2405
|
public func driveManagerNavi(_ driveManager: AMapNaviDriveManager, didArrive wayPoint: AMapNaviPoint) {
|
|
1261
|
-
|
|
1262
|
-
"index": 0
|
|
1263
|
-
])
|
|
2406
|
+
handleWayPointArrived(index: 0, point: wayPoint)
|
|
1264
2407
|
}
|
|
1265
2408
|
|
|
1266
2409
|
public func driveManagerDidEndEmulatorNavi(_ driveManager: AMapNaviDriveManager) {
|
|
1267
|
-
|
|
1268
|
-
onNavigationEnded([:])
|
|
2410
|
+
handleDidEndEmulatorNavi(reason: "did_end_emulator_navi")
|
|
1269
2411
|
}
|
|
1270
2412
|
|
|
1271
2413
|
public func driveManager(_ driveManager: AMapNaviDriveManager, playNaviSound soundString: String, soundStringType: AMapNaviSoundType) {
|
|
1272
|
-
|
|
1273
|
-
"type": soundStringType.rawValue,
|
|
1274
|
-
"text": soundString
|
|
1275
|
-
])
|
|
2414
|
+
handleNavigationSound(soundString, soundStringType: soundStringType)
|
|
1276
2415
|
}
|
|
1277
2416
|
|
|
2417
|
+
/// 兼容一部分 SDK/Swift 导入下的到达终点回调签名
|
|
1278
2418
|
public func driveManager(onArrivedDestination driveManager: AMapNaviDriveManager) {
|
|
1279
|
-
|
|
2419
|
+
handleArrivedDestination(source: "driveManager(onArrivedDestination:)")
|
|
2420
|
+
deactivateNavigationAudioSessionIfNeeded(reason: "arrived_destination_named")
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
/// AMapNaviDriveManagerDelegate 官方到达终点回调
|
|
2424
|
+
public func driveManagerOnArrivedDestination(_ driveManager: AMapNaviDriveManager) {
|
|
2425
|
+
handleArrivedDestination(source: "driveManagerOnArrivedDestination")
|
|
2426
|
+
deactivateNavigationAudioSessionIfNeeded(reason: "arrived_destination_official")
|
|
1280
2427
|
}
|
|
1281
2428
|
|
|
1282
|
-
public func
|
|
2429
|
+
public func driveManagerNeedRecalculateRoute(forYaw driveManager: AMapNaviDriveManager) {
|
|
1283
2430
|
onRouteRecalculate([
|
|
1284
2431
|
"reason": "yaw"
|
|
1285
2432
|
])
|
|
1286
2433
|
}
|
|
1287
2434
|
|
|
1288
|
-
public func
|
|
2435
|
+
public func driveManagerNeedRecalculateRoute(forTrafficJam driveManager: AMapNaviDriveManager) {
|
|
1289
2436
|
onRouteRecalculate([
|
|
1290
2437
|
"reason": "traffic"
|
|
1291
2438
|
])
|
|
1292
2439
|
}
|
|
1293
2440
|
|
|
1294
2441
|
public func driveManager(_ driveManager: AMapNaviDriveManager, update gpsSignalStrength: AMapNaviGPSSignalStrength) {
|
|
1295
|
-
|
|
1296
|
-
onGpsSignalWeak([
|
|
1297
|
-
"isWeak": isWeak
|
|
1298
|
-
])
|
|
2442
|
+
handleGpsSignalUpdate(gpsSignalStrength)
|
|
1299
2443
|
}
|
|
1300
2444
|
}
|
|
1301
2445
|
|
|
@@ -1304,7 +2448,8 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveViewDelegate {
|
|
|
1304
2448
|
|
|
1305
2449
|
public func driveViewDidLoad(_ driveView: AMapNaviDriveView) {
|
|
1306
2450
|
applyViewOptions()
|
|
1307
|
-
|
|
2451
|
+
applyShowUIElementsToActiveViewIfReady()
|
|
2452
|
+
refreshCustomWaypointAnnotations()
|
|
1308
2453
|
scheduleOverviewRouteVisibleRegionRefresh()
|
|
1309
2454
|
onNavigationReady([:])
|
|
1310
2455
|
}
|
|
@@ -1331,45 +2476,14 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveDataRepresentable {
|
|
|
1331
2476
|
guard let naviLocation else {
|
|
1332
2477
|
return
|
|
1333
2478
|
}
|
|
1334
|
-
|
|
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
|
-
])
|
|
2479
|
+
handleNavigationLocationUpdate(naviLocation)
|
|
1345
2480
|
}
|
|
1346
2481
|
|
|
1347
2482
|
public func driveManager(_ driveManager: AMapNaviDriveManager, update naviInfo: AMapNaviInfo?) {
|
|
1348
2483
|
guard let naviInfo else {
|
|
1349
2484
|
return
|
|
1350
2485
|
}
|
|
1351
|
-
|
|
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
|
-
])
|
|
2486
|
+
handleNavigationInfoUpdate(naviInfo)
|
|
1373
2487
|
}
|
|
1374
2488
|
|
|
1375
2489
|
public func driveManager(_ driveManager: AMapNaviDriveManager, showCross crossImage: UIImage?) {
|
|
@@ -1401,6 +2515,20 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveDataRepresentable {
|
|
|
1401
2515
|
|
|
1402
2516
|
public func driveManager(_ driveManager: AMapNaviDriveManager, updateTurnIconImage turnIconImage: UIImage?, turn turnIconType: AMapNaviIconType) {
|
|
1403
2517
|
lastTurnIconType = Int(turnIconType.rawValue)
|
|
2518
|
+
let encodedTurnIcon = encodeTurnIconForLiveActivity(turnIconImage)
|
|
2519
|
+
if let encodedTurnIcon {
|
|
2520
|
+
lastTurnIconBase64 = encodedTurnIcon
|
|
2521
|
+
} else if turnIconImage == nil {
|
|
2522
|
+
NSLog(
|
|
2523
|
+
"[ExpoGaodeMapNaviView][LiveActivity] turnIconImage is nil, keep previous turn icon snapshot"
|
|
2524
|
+
)
|
|
2525
|
+
}
|
|
2526
|
+
NSLog(
|
|
2527
|
+
"[ExpoGaodeMapNaviView][LiveActivity] turnIconType=%d, incomingBase64Length=%d, effectiveBase64Length=%d",
|
|
2528
|
+
Int(turnIconType.rawValue),
|
|
2529
|
+
encodedTurnIcon?.count ?? 0,
|
|
2530
|
+
lastTurnIconBase64?.count ?? 0
|
|
2531
|
+
)
|
|
1404
2532
|
lastTurnIconImageUri = cacheTurnIconImage(
|
|
1405
2533
|
turnIconImage,
|
|
1406
2534
|
prefix: "turn_icon",
|
|
@@ -1419,3 +2547,155 @@ extension ExpoGaodeMapNaviView: AMapNaviDriveDataRepresentable {
|
|
|
1419
2547
|
reemitLastNavigationInfoIfNeeded()
|
|
1420
2548
|
}
|
|
1421
2549
|
}
|
|
2550
|
+
|
|
2551
|
+
// MARK: - AMapNaviWalkManagerDelegate
|
|
2552
|
+
extension ExpoGaodeMapNaviView: AMapNaviWalkManagerDelegate {
|
|
2553
|
+
public func walkManager(_ walkManager: AMapNaviWalkManager, didStartNavi naviMode: AMapNaviMode) {
|
|
2554
|
+
handleNavigationStarted(naviMode)
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
public func walkManagerDidEndEmulatorNavi(_ walkManager: AMapNaviWalkManager) {
|
|
2558
|
+
handleDidEndEmulatorNavi(reason: "walk_did_end_emulator_navi")
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
public func walkManager(_ walkManager: AMapNaviWalkManager, playNaviSound soundString: String, soundStringType: AMapNaviSoundType) {
|
|
2562
|
+
handleNavigationSound(soundString, soundStringType: soundStringType)
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
public func walkManager(onArrivedDestination walkManager: AMapNaviWalkManager) {
|
|
2566
|
+
handleArrivedDestination(source: "walkManagerOnArrivedDestination")
|
|
2567
|
+
deactivateNavigationAudioSessionIfNeeded(reason: "walk_arrived_destination")
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
public func walkManagerNeedRecalculateRoute(forYaw walkManager: AMapNaviWalkManager) {
|
|
2571
|
+
onRouteRecalculate([
|
|
2572
|
+
"reason": "yaw"
|
|
2573
|
+
])
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
public func walkManager(_ walkManager: AMapNaviWalkManager, update gpsSignalStrength: AMapNaviGPSSignalStrength) {
|
|
2577
|
+
handleGpsSignalUpdate(gpsSignalStrength)
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
public func walkManager(_ walkManager: AMapNaviWalkManager, onArrivedWayPoint wayPointIndex: Int32) {
|
|
2581
|
+
handleWayPointArrived(index: Int(wayPointIndex))
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
public func walkManager(_ walkManager: AMapNaviWalkManager, onCalculateRouteFailure error: Error) {
|
|
2585
|
+
onRouteCalculated([
|
|
2586
|
+
"success": false,
|
|
2587
|
+
"errorInfo": error.localizedDescription
|
|
2588
|
+
])
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
// MARK: - AMapNaviWalkViewDelegate
|
|
2593
|
+
extension ExpoGaodeMapNaviView: AMapNaviWalkViewDelegate {
|
|
2594
|
+
public func walkViewEdgePadding(_ walkView: AMapNaviWalkView) -> UIEdgeInsets {
|
|
2595
|
+
driveViewEdgePadding
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2598
|
+
public func walkView(_ walkView: AMapNaviWalkView, didChange showMode: AMapNaviWalkViewShowMode) {
|
|
2599
|
+
if showMode == .overview {
|
|
2600
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
extension ExpoGaodeMapNaviView: AMapNaviWalkDataRepresentable {
|
|
2606
|
+
public func walkManager(_ walkManager: AMapNaviWalkManager, update naviRoute: AMapNaviRoute?) {
|
|
2607
|
+
if let routeLength = naviRoute?.routeLength, routeLength > 0 {
|
|
2608
|
+
currentRouteTotalLength = routeLength
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
public func walkManager(_ walkManager: AMapNaviWalkManager, update naviLocation: AMapNaviLocation?) {
|
|
2613
|
+
guard let naviLocation else {
|
|
2614
|
+
return
|
|
2615
|
+
}
|
|
2616
|
+
handleNavigationLocationUpdate(naviLocation)
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
public func walkManager(_ walkManager: AMapNaviWalkManager, update naviInfo: AMapNaviInfo?) {
|
|
2620
|
+
guard let naviInfo else {
|
|
2621
|
+
return
|
|
2622
|
+
}
|
|
2623
|
+
handleNavigationInfoUpdate(naviInfo)
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
// MARK: - AMapNaviRideManagerDelegate
|
|
2628
|
+
extension ExpoGaodeMapNaviView: AMapNaviRideManagerDelegate {
|
|
2629
|
+
public func rideManager(_ rideManager: AMapNaviRideManager, didStartNavi naviMode: AMapNaviMode) {
|
|
2630
|
+
handleNavigationStarted(naviMode)
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
public func rideManagerDidEndEmulatorNavi(_ rideManager: AMapNaviRideManager) {
|
|
2634
|
+
handleDidEndEmulatorNavi(reason: "ride_did_end_emulator_navi")
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
public func rideManager(_ rideManager: AMapNaviRideManager, playNaviSound soundString: String, soundStringType: AMapNaviSoundType) {
|
|
2638
|
+
handleNavigationSound(soundString, soundStringType: soundStringType)
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
public func rideManager(onArrivedDestination rideManager: AMapNaviRideManager) {
|
|
2642
|
+
handleArrivedDestination(source: "rideManagerOnArrivedDestination")
|
|
2643
|
+
deactivateNavigationAudioSessionIfNeeded(reason: "ride_arrived_destination")
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
public func rideManagerNeedRecalculateRoute(forYaw rideManager: AMapNaviRideManager) {
|
|
2647
|
+
onRouteRecalculate([
|
|
2648
|
+
"reason": "yaw"
|
|
2649
|
+
])
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2652
|
+
public func rideManager(_ rideManager: AMapNaviRideManager, update gpsSignalStrength: AMapNaviGPSSignalStrength) {
|
|
2653
|
+
handleGpsSignalUpdate(gpsSignalStrength)
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
public func rideManager(_ rideManager: AMapNaviRideManager, onArrivedWayPoint wayPointIndex: Int32) {
|
|
2657
|
+
handleWayPointArrived(index: Int(wayPointIndex))
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
public func rideManager(_ rideManager: AMapNaviRideManager, onCalculateRouteFailure error: Error) {
|
|
2661
|
+
onRouteCalculated([
|
|
2662
|
+
"success": false,
|
|
2663
|
+
"errorInfo": error.localizedDescription
|
|
2664
|
+
])
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
// MARK: - AMapNaviRideViewDelegate
|
|
2669
|
+
extension ExpoGaodeMapNaviView: AMapNaviRideViewDelegate {
|
|
2670
|
+
public func rideViewEdgePadding(_ rideView: AMapNaviRideView) -> UIEdgeInsets {
|
|
2671
|
+
driveViewEdgePadding
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
public func rideView(_ rideView: AMapNaviRideView, didChange showMode: AMapNaviRideViewShowMode) {
|
|
2675
|
+
if showMode == .overview {
|
|
2676
|
+
scheduleOverviewRouteVisibleRegionRefresh()
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
extension ExpoGaodeMapNaviView: AMapNaviRideDataRepresentable {
|
|
2682
|
+
public func rideManager(_ rideManager: AMapNaviRideManager, update naviRoute: AMapNaviRoute?) {
|
|
2683
|
+
if let routeLength = naviRoute?.routeLength, routeLength > 0 {
|
|
2684
|
+
currentRouteTotalLength = routeLength
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
public func rideManager(_ rideManager: AMapNaviRideManager, update naviLocation: AMapNaviLocation?) {
|
|
2689
|
+
guard let naviLocation else {
|
|
2690
|
+
return
|
|
2691
|
+
}
|
|
2692
|
+
handleNavigationLocationUpdate(naviLocation)
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
public func rideManager(_ rideManager: AMapNaviRideManager, update naviInfo: AMapNaviInfo?) {
|
|
2696
|
+
guard let naviInfo else {
|
|
2697
|
+
return
|
|
2698
|
+
}
|
|
2699
|
+
handleNavigationInfoUpdate(naviInfo)
|
|
2700
|
+
}
|
|
2701
|
+
}
|