iOS deeplinks not working when the app is completely closed [duplicate] - ios

This question already has answers here:
iOS Deep link callbacks not working when the app is closed
(2 answers)
Application openURL gets called a few seconds after didFinishLaunchingWithOptions
(3 answers)
Closed 4 months ago.
In our app we have a deeplink that when tapped it opens the app to our homepage and then do a push to another section.
When the app is open in the background it works properly but when the app is completely closed it just opens the app, land in the homePage and it stays there.
In the AppDelegate we handle deeplinks in this way:
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let incomingURL = userActivity.webpageURL else { return false }
// Here we call a method to handle the deeplink and open the correct page
return true
}
Here is our json file for the deeplinks
{
"applinks": {
"apps": [],
"details": [
{
"appID": "appIdOne",
"paths": [
"*"
]
},
{
"appID": "appIdTwo",
"paths": [
"*"
]
},
{
"appID": "appIdThree",
"paths": [
"*"
]
}
]
}
}
Is there something missing?
Reading another answer to a similar question iOS Deep link callbacks not working when the app is closed
the issue may be that we don't have "content_available" : true field in our file. If it's the case where should we add that field?
Thanks in advance.

As suggested by Antanas I solved it by handling the deeplink management in application:didFinishLaunchingWithOptions: method which is called when the app opens. Instead when the app is completely closed application: UIApplication, continue userActivity: NSUserActivity is not going to be called.

Related

Universal link not performing action despite url being hit

I've successfully implemented universal links in to my app. The AASA is live on my website, and running the following command in my terminal successfully boots the app as expected:
xcrun simctl openurl booted https://websiteurl.com
Note - the url is different in practice.
For reference, this is my AASA structure:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "identifier.bundle_id",
"paths": ["*"]
}
]
}
}
However, my eventual aim with these universal links is to integrate it into an API which requires a redirect URI, where I send users back to the app.
As a result, I've created a ViewController, imaginatively called CallbackViewController. I will redirect users to this screen when the app is ready.
For now, I've introduced the following code into my AppDelegate file. The aim here is to print 'callback' when a universal link with the phrase 'callback' in is hit. However, when running the initial command in my terminal and adding /callback onto the end, nothing happens.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL, let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
return false
}
if (components.path.contains("callback")) {
print("callback hit...")
}
return true
}
Does anyone know what I'm doing wrong in this function? I'm wondering if it's related to my AASA but unsure.
Thanks!

How to NOT handle some Universal Links programmatically?

My iOS application handles universal links to redirect safari users to my app. So far everything is working great, if a user tap a link to my web site from Google my app is opening instead of my web site like this:
from safari https://my-web-site.com -> my-app
But my app doesn't implement certains features that my web site does, so I would like to programmatically reject some URLs and let my users on safari instead of redirecting him in my app, like this:
from safari https://my-web-site.com -> my-app
OR
from safari https://my-web-site.com?reject -> safari
That should by possible according to Apple documentation:
It’s important to understand that if your app uses openURL: to open a universal link to your website, the link does not open in your app. In this scenario, iOS recognizes that the call originates from your app and therefore should not be handled as a universal link by your app.
Unfortunately that's not what's appending, instead of staying in safari, my user is redirected to my app for a brief moment, then redirected again to safari like this:
from safari https://my-web-site.com?reject -> my-app (briefly) -> safari
here is my code for AppDelegate.swift:
internal func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard let url = userActivity.webpageURL else { return false }
guard let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) else { return false }
let params = urlComponents.queryItems ?? []
if params.contains(where: { $0.name == "reject" }) {
// This line should prevent the app from opening according to Apple's documentation
application.open(url)
return false
} else {
return true
}
}
So anyone have an idea how I could make the rejection of an Universal link the way it's described by Apple's documentation ?
note: the rejection of an universal link need to be done programmatically by the app, according to data stored locally. So adding a path exception in the apple-app-site-association file is not an option in my case :
{
"applinks": {
"apps": [],
"details": [
{
"appID": "XXXXXXXXX.com.my-app",
"paths": [
"*",
"NOT /reject"
]
}
]
}
}
If you prefix an entry in the paths array with "NOT" then you can explicitly prevent a match. So in your example you could do something like
["NOT /settings/*", "NOT /activity/*", "/*"]
which would prevent paths with /settings or /activity prefixes, and then match everything else.
Reference

iOS OneSignal handleNotificationReceived callback not called after app restart

When I run my app from Xcode everything works fine. I get the handleNotificationReceived callback is called and I can read the data from the notification and handle it depending on the data. If I click on a notification the handleNotificationAction callback is called and the same here. If I then minimize the app it works the same - callbacks are called and I can handle the notification.
The problems begin when I terminate the app from the iPhone through the recent app menu and start it from the icon on the desktop. If the app is in the foreground everything works fine like when I start the app from Xcode. When I minimize it I still get the notification but the handleNotificationReceived callback doesn't get called anymore. If I click on a notification the app comes into foreground and then handleNotificationAction is called and shortly after that handleNotificationReceived is also called. As long as the app is in foreground it continues working fine and the callbacks get called. As soon as I minimize the app again handleNotificationReceived doesn't get called anymore.
If I attach the debugger everything starts to work fine again.
Why isn't it called? I am receiving some data in the notifications that I have to save in Core Data.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
AppDelegate.configOneSignal(launchOptions)
return true
}
class func configOneSignal(_ launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Void {
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: false]
OneSignal.initWithLaunchOptions(launchOptions,
appId: "MY_APP_ID",
handleNotificationReceived: { notification in
print("notification received")
AppDelegate.handleNotification(notification)
},
handleNotificationAction: { (result) in
print("notification action")
AppDelegate.handleNotification(result?.notification)
},
settings: onesignalInitSettings)
OneSignal.inFocusDisplayType = OSNotificationDisplayType.notification;
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
}
Xcode version: 10.1
Tested iOS versions: 10, 11, 12
handleNotificationReceived is triggered in background only if you set in the body the following flags (see doc, under section-content-language):
content_available: 1
mutable_content: 1
With the above two flags in the body of the POST, the OS wakes up your application in order to set the state as BACKGROUND. When you application is marked with these state, the handler is triggered.
You can test through Postman.
{ "app_id" : "<your one signal app id>", "included_segments" : ["All"], -> or whatever you want "content_available": "1", "mutable_content": "1", "data": {
"custom_key" : "custom_value" }, "contents": {"en":"notification title"} }
Don't forget to set the headers (Content-Type & Authorization)
Here is an example of usage.

Awake iOS app using silent push notifications [duplicate]

This question already has answers here:
What is Silent Push Notification? When does the device receive it?
(2 answers)
Is possible use silent push to wake up APP and get the VOIP call?
(1 answer)
Closed 5 years ago.
I know this is not the first version of this kind of question - but all information I found seems to be outdated or even wrong. So I decided to ask the question again.
Currently I'm using remote notifications to send notifications to my iOS device. Because I'd like to "awake" my application every hour (even if the app was force closed by the user) my idea was to use silent-push notifications.
Just sending Notifications is working quite well - even in the background or after force-closed by the user. But how to wake my application when it's force-closed to perform a background task by using silent-push-notifications?
func application( _ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
let aps = userInfo["aps"] as! [String: AnyObject] { // remote information
completionHandler(.newData) // call completion handler
}
This is the raw of the notification:
send notification but doesn't perform background task (doesn't awake my app)
{
"aps" : {
"alert" : {
"title" : "..."
},
"content-available" : 1,
"information" : "abc"
}
}
also doesn't perform background task (doesn't wake my app)
{
"aps" : {
"content-available" : 1,
"information" : "abc"
}
}

Get launchOptions when resuming App

I am able to handle the launchOptions value in the application method (since, obviously, the parameter gets passed to it). What I'm doing is basically receiving an image from a user who imported it by selecting my app in the Share menu:
It works fine if the App hasn't already been launched, but I don't see how I get the input parameters if the App is already running and the application method isn't called.
I tried to find a method that would help me like
applicationWillEnterForeGround(_ application: UIApplication, _ launchOptions: [UIApplicationLaunchOptionsKey: Any]?
but without any success.
I assume it's possible, since you can share images to WhatsApp or Facebook too, even when they've already been launched.
Can someone help me out?
Thanks,
Jan
You should implement the application:openURL:options: method as follows (Swift 2):
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
// Do your stuff and return true if you have handled the URL...
// Else
return false
}
Relevant tutorial in Ray Wenderlich
As of Swift 4.2 the signature is:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// Do your stuff and return true if you have handled the URL...
// Else
return false
}
I think you're currently watching in the wrong direction. You should refer to Inter-App communication guide, provided by Apple. If generalise this, you simply need this method, that will handle URI link to your app.
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options;

Resources