Continuing userActivity not working when app isn't in background - ios

I am trying to implement universal linking in an app, and everything works well when the app is in the background. But when the app isn't loaded already, it will flash the correct screen for like a tenth of a second before it goes back to the root view controller. Not sure what's happening here, anyone have any insight? The project only has AppDelegate, no SceneDelegate. continueWithLink will go to the correct VC, and is not the issue.
in my app delegate file:
didFinishLaunchingWithOptions
if let url = launchOptions?[UIApplication.LaunchOptionsKey.url] as? URL {
self.continueWithLink(url: url)
} else if let activityDictionary = launchOptions?[UIApplication.LaunchOptionsKey.userActivityDictionary] as? [AnyHashable: Any] {
for key in activityDictionary.keys {
if let userActivity = activityDictionary[key] as? NSUserActivity {
if let url = userActivity.webpageURL {
self.continueWithLink(url: url)
}
}
}
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let url = userActivity.webpageURL {
self.continueWithLink(url: url)
}
}

Related

How to redirect to a certain screen when opening a dynamic link?

I'm developing an app that can receive Firebase's Dynamic Link. What I want is when a user click a Dynamic Link, the app redirects it to a certain UIViewController. So I have a code that looks like this on my AppDelegate.swift file:
#available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
//return GIDSignIn.sharedInstance().handle(url)
return application(app, open: url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String, annotation: "")
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
// On progress
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
print("open url = open dynamic link activity")
print("url = \(dynamicLink)")
let destinationVC = UIStoryboard(name: "DynamicLink", bundle: nil).instantiateViewController(withIdentifier: "DynamicLinkView") as? DynamicLinkVC
self.window?.rootViewController?.navigationController?.pushViewController(destinationVC!, animated: true)
} else {
print("open url = none")
}
return GIDSignIn.sharedInstance().handle(url)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// On progress
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
print("dynamic link = \(dynamiclink)")
}
if handled {
let destinationVC = UIStoryboard(name: "DynamicLink", bundle: nil).instantiateViewController(withIdentifier: "DynamicLinkView") as? DynamicLinkVC
self.window?.rootViewController?.navigationController?.pushViewController(destinationVC!, animated: true)
}
return handled
}
So what happened when I click the link the app opens up immediately but it doesn't redirects to the desired UIViewController that I wanted (in this case destinationVC). It directly went to the login page as usual. But in the debug area, the link appears like this =
dynamic link = Optional(https://xxxx], match type: unique, minimumAppVersion: N/A, match message: (null)>)
Unfortunately I couldn't record the log messages when the app is not built by Xcode.
I'm very confused by this, what's wrong with my code? I'm new to iOS development so I'm not sure where did I do wrong. If you need more information feel free to ask and I will provide it to you. Any help would be appreciated. Thank you.
If your rest-of-code is working fine, and you are just facing issue while navigating to another view controller, then this solution will work for you.
If you want to open particular ViewController, while clicking on dynamic link, then update your code written within restorationHandler, below updated code will help you to redirect/navigate to particular View Controller
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// On progress
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
print("dynamic link = \(dynamiclink)")
}
if handled {
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "DynamicLink", bundle: nil)
if let initialViewController : UIViewController = (mainStoryboardIpad.instantiateViewController(withIdentifier: "DynamicLinkView") as? DynamicLinkVC) {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
return handled
}
Hope this will resolve your issue.

SWIFT :- Universal linking in swift is not working

I am using universal linking in my project.
I have made apple-app-site-association file in server.
I enable in developer account, Xcode for associate domains and I wrote
applinks:www.laundry.com
The code used in AppDelegate is:-
//Universal links in swift delegatemethod.
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: #escaping ([Any]?) -> Void) -> Bool
{
if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
let url = userActivity.webpageURL!
let userurl = url.absoluteString
// print(url.absoluteString)
//handle url
if defaultValues.value(forKey: accessToken) != nil
{
print("user url is:",userurl)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Pickup", bundle: nil)
let innerPage: PickupController = mainStoryboard.instantiateViewController(withIdentifier: "PickupController") as! PickupController
innerPage.selectedfrom = "Deeplink"
self.window?.rootViewController = innerPage
}else{
setRootControllerBeforeLogin()
}
}
return true
}
But it is not working, please help to me.
I once used dynamic links of firebase, and override another function in appDelegate like below.
func application(_ application:UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {
print("I have received a URL through custom url scheme : \(url.absoluteString)")
// tot do with dynamic link....
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
return true
} else {
// handle others like twitter or facebook login
}
}
Do it on App delegate
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
if let url = userActivity.webpageURL {
let component = URLComponents.init(string: url.absoluteString)!
print(component.path)
}
return true
}

Firebase Deeplink not calling application:continueUserActivity:restorationHandler function of AppDelegate in Swift 3

I am using firebase Deeplink URL to open my app's specific section. It is working well when app running in background but when I killed the app and click deeplink url from outside than I don't know how to handle that case, I mean where I should write my condition to get the parameters of url.
This method of app delegate called when app in background
#available(iOS 8.0, *)
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
guard let dynamicLinks = DynamicLinks.dynamicLinks() else {
return false
}
let handled = dynamicLinks.handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
if let dynamicLink = dynamiclink, let _ = dynamicLink.url
{
var path = dynamiclink?.url?.path
path?.remove(at: (path?.startIndex)!)
let delimiter = "/"
var fullNameArr = path?.components(separatedBy: delimiter)
let type: String = fullNameArr![0]
let Id: String? = (fullNameArr?.count)! > 1 ? fullNameArr?[1] : nil
if(type == "games")
{
self.callGameDetailView(gameId: Id! , gameType: "created", notificationId: "NIL" )
}else{
var paths = dynamicLink.url?.path
paths?.remove(at: (path?.startIndex)!)
self.setRewardViewController(paths!)
}
} else {
// Check for errors
}
}
return handled
}
but it will not call open url method when I killed the app and hit the dynamic link url:
#available(iOS 9.0, *)
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any])
-> Bool {
return self.application(application, open: url, sourceApplication: nil, annotation: [:])
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let dynamicLink = DynamicLinks.dynamicLinks()?.dynamicLink(fromCustomSchemeURL: url)
if let dynamicLink = dynamicLink
{
var path = dynamicLink.url?.path
path?.remove(at: (path?.startIndex)!)
let delimiter = "/"
var fullNameArr = path?.components(separatedBy: delimiter)
let type: String = fullNameArr![0]
let Id: String? = (fullNameArr?.count)! > 1 ? fullNameArr?[1] : nil
if(type == "games")
{
self.callGameDetailView(gameId: Id! , gameType: "created", notificationId: "NIL" )
}else{
var paths = dynamicLink.url?.path
paths?.remove(at: (path?.startIndex)!)
self.setRewardViewController(paths!)
return true
}
}
return FBSDKApplicationDelegate.sharedInstance().application(
application,
open: url,
sourceApplication: sourceApplication,
annotation: annotation)
}
In short I have no Idea how to handle the dynamic link when app runs first time or run after killing the app?
I also have same issue, you need to get NSUserActivity from launchOptions
var launchURL :URL? = nil
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
....
// this code should have worked but not working for me with Xcode 9
// if let userActivityDictionary = launchOptions?[.userActivityDictionary] as? [UIApplicationLaunchOptionsKey : Any],
// let auserActivity = userActivityDictionary[.userActivityType] as? NSUserActivity {
// launchURL = auserActivity.webpageURL
// }
if let userActDic = launchOptions?[UIApplicationLaunchOptionsKey.userActivityDictionary] as? [String: Any],
let auserActivity = userActDic["UIApplicationLaunchOptionsUserActivityKey"] as? NSUserActivity{
NSLog("type \(userActDic.self),\(userActDic)") // using NSLog for logging as print did not log to my 'Device and Simulator' logs
launchURL = auserActivity.webpageURL
}
...
}
func applicationDidBecomeActive(_ application: UIApplication) {
if let url = self.launchURL {
self.launchURL = nil
DispatchQueue.main.asyncAfter(deadline: .now()+2.0, execute: {
// wait to initalize notifications
if let dynamicLinks = DynamicLinks.dynamicLinks() {
NSLog("handling \(dynamicLinks)")
dynamicLinks.handleUniversalLink(url) { (dynamiclink, error) in
if let link = dynamiclink?.url {
NSLog("proceessing \(dynamicLinks)")
let strongMatch = dynamiclink?.matchConfidence == .strong
// process dynamic link here
self.processDynamicLink(withUrl: link, andStrongMatch: strongMatch)
}
}
}
})
}
}
I also facing this same issue all day. Firebase SDK does not handle this edge case and didn't mention anywhere in their documentation. Very frustrating!
Found a solution after the investigation for iOS 13 and later OS.
Firebase Dynamic link is working and also able to redirect to a specific page even when the app runs the first time or run after killing the app.
Have the below code in the SceneDelegate instead of AppDelegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let firstUrlContext = connectionOptions.userActivities.first,let url = firstUrlContext.webpageURL {
DynamicLinks.dynamicLinks().handleUniversalLink(url) { (dynamiclink, error) in
if let dynamiclink = dynamiclink {
self.handleDynamicLink(dynamiclink)
}
}
}
}
The two openURL AppDelegate methods that you are referencing are called when the application is opened by use of a URI scheme. URI scheme functionality will only work in very specific scenarios. In iOS 9, Apple switched to Universal Links, which actually call the function application:continueUserActivity:restorationHandler:.
This function does not call the openURL methods so all of your Universal links handling will have to be done in the continueUserActivity that you mentioned first.
For the sake of saving yourself a lot of trouble in handling other edgecases, I'd suggest moving to another 3rd party provider like Branch (Full disclosure, I work there) since they bundle all of this handling into one callback and provide more functionality and attribution related services that are not available to Firebase users.
In application:didFinishLaunchingWithOptions: method, you need to register your customURLScheme.
FirebaseOptions.defaultOptions()?.deepLinkURLScheme = YOUR_URL_SCHEME

Universal links, continueUserActivity and sourceApplication not being called

I finally manage to do universal links, if I tap the link it will open my app. but it doesn't show up in continue user activity or source application. Because I want to redirect it to the specific view controller. For example if I open "https://www.myWeb.com/forgotPassword", it will redirect to forgotPasswordViewController, and I need to read the link.
Why doesn't it show up in continue user activity?
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
print(url)
let urlHost : String = url.host as String!
print("HELLO")
let main : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let inner : ResetPasswordViewController = main.instantiateViewController(withIdentifier: "ResetPasswordViewController") as! ResetPasswordViewController
self.window?.rootViewController = inner
self.window?.makeKeyAndVisible()
return true;
}
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
let url = userActivity.webpageURL!
print(url)
print("HELLO WORLD")
}
return true
}
And this is what happened with the source application; can someone tell me why it becomes like that?
SOLVED
it's just because of type Data, i put AnyObject instead of Any.
but the compiler doesn't tell me if AnyObject can't be used
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
print("Continue User Activity: ")
if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
let url = userActivity.webpageURL!
print(url.absoluteString)
//handle url
}
return true
}

Branch.io - link opening the app but not getting data in it

Branch.io link not getting data if app opened installed already. When app installed link opens the app directly but data missing. But if i redirect to app store then click again on branch link and open the app directly then data comes. Please guide, posting the code below.
Update:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
let branch: Branch = Branch.getInstance()
branch.setDebug()
branch.initSessionWithLaunchOptions(launchOptions, andRegisterDeepLinkHandler: {params, error in
if error == nil {
// params are the deep linked params associated with the link that the user clicked -> was re-directed to this app
// params will be empty if no data found
print("params: %#", params.description)
print(params["event_id"])
if let url = params["event_id"] as? NSInteger {
let strEventID = String(url)
print(strEventID)
})
self.window?.rootViewController = nav
self.window?.makeKeyAndVisible()
return true
}
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
Branch.getInstance().handleDeepLink(url)
if(sourceApplication == "com.linkedin.LinkedIn")
{
if(LISDKCallbackHandler.shouldHandleUrl(url))
{
return LISDKCallbackHandler.application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
}
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
// handler for Universal Links
Branch.getInstance().continueUserActivity(userActivity)
return true
}
// Called when a notification is received and the app is in the
// foreground (or if the app was in the background and the user clicks on the notification).
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)
{
Branch.getInstance().handlePushNotification(userInfo)
if(UserSingleton.sharedInstance.accessToken != kEmptyString)
{
if let aps = userInfo["aps"] as? NSDictionary {
var title = kEmptyString
var message = kEmptyString
var inviteID = kEmptyString
var statusType = kEmptyString
if let inviteIDLocal = aps.valueForKey("id") as? NSNumber
{
inviteID = "\(inviteIDLocal)"
}
else if let inviteIDLocal = aps.valueForKey("id") as? String
{
inviteID = inviteIDLocal
}
else
{
inviteID = "0"
}
if let statusTypeLocal = aps.valueForKey("status_type") as? String
{
statusType = statusTypeLocal
}
if let titleLocal = aps.valueForKey("alert")?.valueForKey("title") as? String
{
title = titleLocal
}
if let messageLocal = aps.valueForKey("alert")?.valueForKey("body") as? String
{
message = messageLocal
}
CommonFunctions.addNotificationBar(title,message: message, inviteID: inviteID,statusType: statusType)
}
}
}
After spending an day, finally came to know the reason.
// Respond to Universal Links
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([**Any**]?) -> Void) -> Bool {
// pass the url to the handle deep link call
Branch.getInstance().continue(userActivity)
return true
}
"Any" should be actually "AnyObject".

Resources