Trigger onOpenUrl with specific url programmatically within SwiftUI App - ios

Circumstances
I've got a SwiftUI App with deep link support. When .onOpenUrl is triggered, the app navigates to a specific screen. Every view can listen to that deep link url and therefore has all information to properly set the relevant states (like the TabView selecting a specific tab).
I use deep links for Widgets.
Now that my app supports push notifications, I want to use that deep link navigation handling to open a specific screen based on the push notifications userInfo that comes from the according UIApplicationDelegate method.
Idea
The idea is to generate a deep link url from that user info and pass it down the view hierarchy so that every view can react to .onOpenUrl and set state based on the opened push notification. That way I don't have to add an extra EnvironmentObject to the environment and listen to .onChange(of: someUserInfoInsideTheEnvironment) in every view, duplicating the existing .onOpenUrl handling for deep links.
Question
Is there a way to manually (programmatically) trigger .onOpenUrl with a specific url?
Like setting a specific environment value or -object so that every view in the view hierarchy will call .onOpenUrl with my own deep link url?

Related

Quit the application on a specific view

I have a doubt:
I have an app with 10 views. I want that, if the user is on View1 and sends the app to the background, it terminates the application (exit (0)). But I wanted this to happen only on View1, on the other screens, if the app goes to the background and then returns, it will continue where it left off.
What can I do?
Apple's guidelines seem to be strictly against terminating your app programmatically (for example, with exit()); it would go against what iOS users expect of how apps work.
Instead, I recommend the following approach:
When the app is sent to the background (applicationWillResignActive(_:) is called), check which view controller is currently being displayed.
If it's such that you wish to start over next time the app is brought to the foreground, just reset the app window's root view controller to whatever the initial view controller of your app is (typically, it involves reloading the inital view controller from Main.stroyboard, but your setup could be different).
You can not choose at runtime whether your app goes to the background or is terminated when the user presses the home button ("multitasking"); that is set in stone in your Info.plist file at build time.
Also, remember that even if you are in the screen that you wish to preserve when the user resumes, your app might be terminated by the system while it is in the background (to reclaim scarce system resources), so in that case it will still start from the initial screen. To prevent this, you might want to check out the APIs for state preservation and restoration.
Here is another SO question asking how to find the identity of the current view controller. Why not query the current view when you receive applicationWillResignActive indicating that your app is going to move to the background and then choose the action you want?
As far as I understand your description Preserving and Restoring State is what you are looking for.
Excerpt from Documentation:
The preservation and restoration process is mostly automatic, but you need to tell iOS which parts of your app to preserve. The steps for preserving your app’s view controllers are as follows:
Required
Assign restoration identifiers to the view controllers whose
configuration you want to preserve; see Tagging View Controllers for
Preservation.
Tell iOS how to create or locate new view controller objects at
launch time; see Restoring View Controllers at Launch Time.
Optional
For each view controller, store any specific configuration data needed to return that view controller to its original configuration; see Encoding and Decoding Your View Controller’s State.
Here is a link to Preserving Your App’s Visual Appearance Across Launches

URL Scheme to open specific part of app

I have an application which can show user-created countdowns.
I have a Today extension widget which shows a few of the user's countdowns and when you tap one, it opens the app and jumps to the view controller for that specific countdown.
I've implemented this via URL scheme. When I tap on a countdown in the widget, it uses the url scheme to open the app. In application(_: open: options:), the app delegate:
Gets the countdown's UUID from the opened URL
Gets the index of the countdown object with that ID in the main view controller's array of countdowns (or returns false if it can't find a countdown with that ID)
Calls dismiss(animated: false) on the main view controller to get rid of any presented view controllers
Calls popToRootViewController(animated: false) on the main view controller's navigation controller
Performs a segue that shows the countdown
This all works great. When I tap a countdown in the widget (or even just type in the URL with a known UUID in Safari) then the app opens up straight to the right countdown.
But it only works if the app was already suspended in the background. If the app isn't open yet, it just opens the app like normal, I guess because the main view controller isn't loaded yet when the app is told to open the URL. How can I get around this? Is there a different or better way I should be implementing this?

What architecture can I use to change screens in Swift when there's an event outside of the current view?

For example, I have a Notification that occurs when there is an "unauthorized" error returned from the api server that should bring the user back to the login screen. This event could appear anywhere in the program.
Do I create a new viewless controller to manage states and have it monitor for this notification and then present the login view controller?
I'm thinking about push notifications too, received by the app delegate. Some of these may cause the data model to get updated and then the screen to change. Who should make the screen change? In the past I put all this in the AppDelegate. But there must be a more elegant way!
I also found out about FlowControllers. But they don't play nicely with Interface Builder, at least according to this solution.
Please let me know if you need more specific information about my project.

IOS push Notifications Deep linking?

I have implemented Push notifications and deep link in my app in traditional method using lot of switch cases and creating controller objects and redirecting to that controller but now code is getting unmaintainable because of lot of new scenario.
So I want to know how to handle deep link with push notifications, can URL Schemes work in my case and if URL schemes can work what payload should I send in the push message.
I just did this for my app. It all hinges on how your app is architected, i.e. how you navigate. Our app has a set of "home" pages, i.e. the top level things you can do. We already had the ability to navigate from anywhere back to a home page (by popping the current VC stack and closing any/all modals and then going to the new home page). To that, we added that as each VC loads, it checks state and sees if there is something it should do (configure itself, or push another VC). Once a VC has acted on state which applies to it, it clears that state.
Once you have built your mechanism to navigate to a particular spot, when you receive a push you just set your state and call whatever function navigates you back to the home page. Then that page checks state, does the right thing, and so on.

Global app remote notification response ios

I would like to implement a similar response system for push notifications throughout my app. When a remote notification appears and the application is in the active state I would like to place a button temporarily on the screen that performs the same action regardless of where it is in the app.
The only way I can think to do this is to create the same response to notification method in each of the app's many view controller.
Is there any way to do this in the app delegate, tab bar, or navigation bar so that the same response would apply to multiple views rather than placing the same function in each view controller separately?
Please advise and thanks
If I understood your question correctly: your problem is not related to notifications at all, but rather how to place a button on top of all views. A common way would be to add it as a subView to the window.
As a starting point: AwesomeMenu on GitHub

Resources