Mapbox Navigation, Rerouting Issue in iOS SDK - ios

Navigation keeps on constantly rerouting after every route progress even though the user device location is on the same route. I thought Mapbox automatically handles rerouting only when the user leaves the current route. After I read this part of the documentation, I thought I needed to handle it manually.
Based on documentation, I used below code to handle rerouting manually but the code is deprecated.
func navigationViewController(_ navigationViewController: NavigationViewController, shouldRerouteFrom location: CLLocation) -> Bool {
return navigationViewController.routeController.userIsOnRoute(location)
}
So crash redirects me to this part of Mapbox SDK
#available(*, deprecated, renamed: "navigationService", message: "NavigationViewController no longer directly manages a RouteController. See MapboxNavigationService, which contains a protocol-bound reference to the RouteController, for more information.")
/// :nodoc: obsoleted
#objc public final var routeController: RouteController! {
get {
fatalError()
}
set {
fatalError()
}
}
but navigationService not containing userIsOnRoute function. Is there an alternative function I could use, or is this a bug?

This issue appears to be a bug. Base on #luugiathuy report if you just change SDK to below code if will fix everything, voice and rerouting problem
index 47d8132..bc44ed7 100644
--- a/ios/Pods/MapboxCoreNavigation/MapboxCoreNavigation/NavigationService.swift
+++b/ios/Pods/MapboxCoreNavigation/MapboxCoreNavigation/NavigationService.swift
## -127,7 +127,7 ## public protocol NavigationService: CLLocationManagerDelegate, RouterDataSo #objc(MBNavigationService)
public class MapboxNavigationService: NSObject, NavigationService, DefaultInterfaceFlag {
- typealias DefaultRouter = RouteController
+ typealias DefaultRouter = LegacyRouteController
/**
The default time interval before beginning simulation when the `.onPoorGPS` simulation
In MapboxNavigationService change RouteController to LegacyRouteController and everything will work as expected.
The issue is on for almost 4 months, modifying SDK is not good idea but this is and alternative solution until Mapbox fix this issue.

Related

Implemented iOS AppIntents don't show in Shortcuts

I'm trying to test out the new AppIntents API that is currently on iOS16 Beta. Looking at the documentation, the implementation seems pretty straight forward, but after implementing it, I'm not seeing my AppIntent in the Shortcuts app. The device is running iOS 16.0.
This is how I implemented the AppIntent:
import AppIntents
struct DoSomethingIntent: AppIntent {
static var title: LocalizedStringResource = "This will do something"
static var description = IntentDescription("Does something")
func perform() async throws -> some PerformResult {
return .finished(value: "Done")
}
}
According to the documentation the Shortcuts app should be able to find my AppIntent after my app gets installed, but I see that's not the case. Does anybody know what my implementation is missing?
AppIntents APIs are a little bit new and have strange behaviours and the documentation is very poor.
In my case, I was able to make them work by adding the \(.applicationName) parameter to the phrase. Try this:
struct LibraryAppShorcuts: AppShortcutsProvider {
#AppShortcutsBuilder static var appShortcuts: [AppShortcut] {
AppShortcut(intent: DoSomethingIntent(), phrases: ["Do something with \(.applicationName)"])
}
}
First you need to select your Xcode-beta.app via xcode-select
Clean derived data
Kill your app & shortcut app
Add a shortcut library in your code
struct LibraryAppShorcuts: AppShortcutsProvider {
#AppShortcutsBuilder static var appShortcuts: [AppShortcut] {
AppShortcut(intent: DoSomethingIntent(), phrases: ["My something phrase"])
}
}
Build

How to exclude code from AppExtension? #available(iOSApplicationExtension, unavailable) does not work

I use a custom tool class across different projects which provides some basic, shared methods.
While I can use this class in most projects without any problem, I cannot compile one project any more, which includes an AppExtension / Widget.
This code fails:
class var applicationInterfaceStyle: UIUserInterfaceStyle {
// deactivated method code and only return default value...
return .unspecified
}
'UIUserInterfaceStyle' is only available in application extensions for iOS 12.0 or newer
I tried to add #available(iOSApplicationExtension, unavailable) to this message, but the error is still the same:
#available(iOSApplicationExtension, unavailable)
class var applicationInterfaceStyle: UIUserInterfaceStyle {
// deactivated method code and only return default value...
return .unspecified
}
Why doesn't this exclude the method completely from being compiled for the extension?
Xcode itself proposes to fix the error by adding #available(iOSApplicationExtension 12.0, *). But this does not work as. Additionally I would prefer to exclude the code completely from the extension. How can this be done?

how to find out the number of reroutes in a step-by-step navigation?

I'm new to Mapbox development. I'm wondering if there is a way to find out how many reroutes occurred in one navigation? Any example in iOS/Swift would be even better. Many thanks.
You can listen to the RouteControllerDidReroute notification
For extra data and more information you can register to the relevant delegate: RouterDelegate methods of the RouteController
Mainly the func router(_ router: Router, willRerouteFrom location: CLLocation)
Which according to the documentation:
Called immediately before the router calculates a new route.
This method is called after router(:shouldRerouteFrom:) is called, and before router(:didRerouteAlong:) is called.
Lastly, if one uses the default NavigationViewController supplied by Mapbox.
You can register as it's delegate (NavigationViewControllerDelegate) to get the following updates:
func navigationViewController(_ navigationViewController: NavigationViewController, willRerouteFrom location: CLLocation?)
func navigationViewController(_ navigationViewController: NavigationViewController, didRerouteAlong route: Route)

How to properly extend DatabaseReference in Firebase iOS SDK v4

I have an app that was originally developed in Swift 2 / Xcode 7.3.1 using the Firebase iOS SDK v2.5.1 which is currently being updated to the latest versions of Swift/Xcode, which entails also updating the Firebase SDK.
We have hundreds of unit tests that were developed that, for the most part have been easy to update, but there are a few in particular that are tricky due to the way the old Firebase SDK was structured (and thus how it was used).
Originally, because nearly all Firebase database functionality was encompassed in one "Firebase" class, we created a custom class that inherited from the Firebase class that overrode several methods. In the latest SDK, functionality has been split further into different classes (namely the separate of Database and DatabaseReference), and most of the methods that were overridden are now a part of the DatabaseReference class in the FirebaseDatabase framework.
To make this a bit more tangible.
Old code:
class FirebaseTest: Firebase {
override func childByAutoId() {
//generate and save Auto ID internally to be used later for testing/validation
super.childByAutoID();
}
//many other overridden methods
}
//Unit tests
let fbref = FirebaseTest(url: "my-firebase.firebaseio.com/test");
// etc
The old Firebase SDK would return a Firebase reference to the base URL provided in the constructor, and because many of the properties we used were members of Firebase, all of our testing worked.
Following the SDK migration guide, I end up with the following code (simply replacing Firebase with DatabaseReference):
class FirebaseTest: DatabaseReference {
override func childByAutoId() {
//generate and save Auto ID internally to be used later for testing/validation
super.childByAutoID();
}
//many other overridden methods
}
//Unit tests
let fbref = FirebaseTest(fromUrl: "my-firebase.firebaseio.com/test")
// etc
Now, immediately, there is a problem with the above code that prevents it from compiling: the DatabaseReference constructor does not take any arguments. I can change it to the following
let fbref = FirebaseTest();
but now I know that, while it will compile, the tests will absolutely fail. The tricky part is that, in the latest SDK, database references are only supposed to be retrieved from a Database as follows:
//don't do this!
let fbref = DatabaseReference(); //will compile, but will break at runtime. Upon inspection in the debugger, there are several internal properties that should be set that are null. Those internal properties are likely all set correctly if the database reference is obtained correctly
//do it one of these ways
let fbref2 = Database.database().reference();
let fbref3 = Database.database().reference(fromUrl: "my-firebase.firebaseio.com/test") //also have access to this "reference(fromUrl: )" method from Database.database()
let fbref4 = Database.database().reference(withPath: "/test") //also have access to this "reference(withPath: )" method from Database.database()
So, hopefully my conundrum is becoming clear -- because I can only retrieve a correctly-initalized DatabaseReference from a Database, rather than my version of DatabaseReference that has overridden methods for testing, I'm fairly stuck.
Also, I have looked into creating an extension of Database itself as follows:
class FirebaseTest: DatabaseReference {
override func childByAutoId() {
//generate and save Auto ID internally to be used later for testing/validation
super.childByAutoID();
}
//many other overridden methods
}
class FirebaseDatabaseTest: Database {
override func reference(fromUrl: String) {
return FirebaseTest();
}
}
let fbref = FirebaseDatabaseTest().reference(fromUrl: "my-firebase.firebaseio.com/test")
But, even though I am intercepting the url in the overridden reference method, there's no clear way for me to "set up" the DatabaseReference the correct way using that URL.
Thoughts?

Accidentally overriding getter with swift extension - Only during runtime when app enters foreground again

The last 2 days i brooded over a strange behavior i found in my iOS app. It was one of these moments when you start to have doubts about everything. I found the problem and fixed it. But i want to write this here to search for answers and gain knowledge about the system behind.
I am the developer of "Controller for HomeKit", an app to control HomeKit devices. In HomeKit you have HMActionSets to execute many changes at once. E.g. Turn on all lights.
Executing HMActionSet is a basic functionality and worked always. Here with a swipe of UITableViewCell.
let performAction = UIContextualAction(style: .normal, title: AppStrings.Actions.perform, handler: { (ac: UIContextualAction, view: UIView, success: #escaping (Bool) -> Void) in
self.home?.executeActionSet(selectedActionSet, completionHandler: { (error: Error?) in
if let err = error {
UIApplication.printToConsole(text: err)
success(false)
return
}
success(true)
})
})
BUT suddenly it stopped working flawlessly with a new development version. It took me a while to reproduce the situation, when it wasn't executing the action set.
Every time i start the app from scratch, everything works.
If i execute the HMActionSet right after navigating from the previous UIViewController, everything works. (Most common use case)
It stops working when being in the view, press the home button, reentering the app. After that all executions won't work, until going one view backwards and forward again.
Console logs this error:
Error Domain=HMErrorDomain Code=2 "Object not found." UserInfo={NSLocalizedDescription=Object not found.}
I walked backwards every commit until the problem was solved. After digging in the dark in a too big commit, i found the root cause.
But why am i not getting compile errors? Why does going to the home screen breaks it?
For a new feature i needed a new way to identify a HomeKit object on multiple devices, because the .uniqueIdentifier parameter is salted on every device.
import Foundation
import HomeKit
protocol Identifyable {
func getUniqueIdentifier() -> String?
}
extension HMActionSet: Identifyable {
func getUniqueIdentifier() -> String? {
return self.name.toBase64()
}
}
I created a swift protocol and made an extension to HMActionSet. Of course now that i found the error it looks stupid, to name the method like a getter. But this should not be the discussion now. It seems like this methods overrides the attribute of HMActionSet. When executing the actionSet internal functions accidentally use the wrong uniqueIdentifier, therefore the error is correct. (No object found).
/*!
* #brief A unique identifier for the action set.
*/
#available(iOS 9.0, *)
open var uniqueIdentifier: UUID { get }
If i name the method func uniqueIdentifier() -> String? Xcode immediately shows me a warning.
Method 'uniqueIdentifier()' with Objective-C selector 'uniqueIdentifier' conflicts with getter for 'uniqueIdentifier' with the same Objective-C selector
As i know HomeKit is written in Objective-C. I am using swift 4.
My questions to you:
Why are there no compiler errors (getUniqueIdentifier())?
If its a runtime problem mixing a swift extension into a objective-c framework, why does it only occur when reentering the app and not at the first start or later?
Looking forward to read your explanations about the problem that stole my sleep. :)

Resources