-1

I created a custom URL scheme to launch my app from other apps. This works from Safari if the app isn't open. It loads AppDelegate with function:

func application(_ app: UIApplication, open url: URL, options:  [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool

The issue is that when I have the app open, and place it in the background by hitting the home button. The variable that I have set to receive the text in AppDelegate is not getting hit again. I have a notifier set up in my main VC that works when I bring the app back into the foreground, but the variable that I reference on viewDidLoad is empty since it's reading it from AppDelegate. According to Apple's docs, when a custom url scheme is created, it's going to hit the function above.

The system delivers the URL to your app by calling your app delegate’s application(_:open:options:) method.

There is a function for applicationWillEnterForeground, but I'm not sure how to receive the custom URL into that function if the method isn't called.

Here is what I have so far:

AppDelegate:

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var receivedURL: URL?

    func application(_ app: UIApplication, open url: URL, options:  [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {

        receivedURL = url
        return true
    }

In MainViewController:

    let appDelegate = UIApplication.shared.delegate as? AppDelegate

    override fun viewDidLoad() {
       if appDelegate?.receivedURL != nil {
           urlToDecodeTextView.text = appDelegate?.receivedURL?.absoluteString
        }

NotificationCenter.default.addObserver(self, selector: #selector(handleLinks), name: UIApplication.willEnterForegroundNotification, object: nil)


    }

   @objc func handleLinks(notification: Notification) {
        print("made it back")  <-- This prints
        let test = appDelegate?.receivedURL <-- this is always nil
        urlToDecodeTextView.text = test?.absoluteString
    }

This is the original code that I had. This code works great if the app isn't open, but not if the app is running in the background. I did notice the appdelegate function is ran everytime, but when the notifier happens, the value is nil - even though it was set in the appdelegate.

What I'm ultimately trying to do is be able to copy a URL from an email (text or URL), and share with my app. When it's shared, my app should open with the url in the appropriate textview. I figured it may be easier to use a custom URL scheme and handle rewriting the link, but this has proven to be a challenge.

Nutrion
  • 53
  • 1
  • 9
  • `application(_:open:options:)` is called when opened via custom URL scheme even if from the background. – rmaddy May 19 '19 at 15:52
  • 2
    `viewDidLoad` method is already called and will not be called again. You should set a global variable in `AppDelegate` and set that within `application(_:open:options:)` method (which will be called when open from the other app). Then read the variable from `viewWillAppear` method. If you have different `viewController` opened then you still won't get it. You should navigate to proper `viewController` (eg. poping back to `rootViewController` etc) when the app is opened via URL scheme. – RJE May 19 '19 at 15:56
  • @RJE I set the global variable in appdelegate, but it doesn't appear to hit the viewWillAppear method in the primary VC. It does hit the function in appdelegate again, but if the application is running, the viewWillAppear method isn't being hit. The screen this needs to be sent to is the primary VC, and it's the one that's opened. – Nutrion May 19 '19 at 21:49
  • None of the view controller life cycle methods are called when an app returns to the foreground. – rmaddy May 19 '19 at 22:24
  • See https://stackoverflow.com/questions/49961541/handle-deep-link-notification for a practical solution. – rmaddy May 19 '19 at 22:27
  • Thanks @rmaddy - the link you posted looks close, but when I change my code like that one everything stops working. Initially, sending the link to my unopened app works fine, but sending to an already opened app does not work. Making those changes stopped everything from working. – Nutrion May 20 '19 at 00:18
  • Since there are no answers on your question yet, feel free to update your question with your relevant updated code showing what you have tried and clearly explain where things are going wrong. – rmaddy May 20 '19 at 00:20
  • I think `viewWillAppead` or any other life cycle method won't hit if the view is already opened. You can try posting a Notification and catch it on any relevant `viewController`. – RJE May 20 '19 at 04:49
  • Thanks @RJE. I've edited my OP to show my code. The notifications work when coming back into the foreground, but the variable from appdelegate is always nil. The variable from appdelegate is not nil if the app is not running. – Nutrion May 20 '19 at 10:48

1 Answers1

0

instead of this notification

NotificationCenter.default.addObserver(self, selector: #selector(handleLinks), name: UIApplication.willEnterForegroundNotification, object: nil)

You can do something like this

Some publicly accessible notification NSNotification.Name

let customNotifKey = NSNotification.Name("InterAppURLReceived")

Then change listener

var receivedURL: URL? {
    didSet {
        if receivedURL != nil {
            NotificationCenter.default.post(name: customNotifKey, object: nil)
        }
    }
}

finally catching the notification in VC

        NotificationCenter.default.addObserver(self, selector: #selector(handleMethod(_:)), name: customNotifKey, object: nil)

Now you VC will know when the variable is set.

First, check the variable in viewWillAppear method. if not received expect it to notify you when received

RJE
  • 781
  • 6
  • 14
  • Thanks! This appears to have fixed the 'foreground' issue, but it doesn't appear to work if another app launches mine with a custom URL. It may be an xcode issue, but while debugging, I see it hit the line for setting receiveURL variable, but it never hits viewDidLoad in the main VC. If the app is running already and I send a custom URL, everything works as intended. – Nutrion May 22 '19 at 11:49
  • What do you mean it didn’t hit viewDidLoad. Notification can be use for background and foreground scenario. For new launch you just check the Variable in viewWillAppear method. You are simply confused about the order that each method call by the system in 2 scenarios. You can put some break points and check which method hit first in your 2 scenarios and act accordingly – RJE May 22 '19 at 12:18
  • It was because I changed the way the debugger was attaching to the running app. I changed it back, and it's fine. This doesn't work exactly the way that I want, but I think I have another issue. Thank you for all of your help! – Nutrion May 23 '19 at 01:17