ionic-team / capacitor

Build cross-platform Native Progressive Web Apps for iOS, Android, and the Web ⚡️
https://capacitorjs.com
MIT License
12.11k stars 1k forks source link

bug: iOS ‘appUrlOpen’ event provided by App plugin doesn't work when App is opened from an URL for the first time with SceneDelegate #6662

Open carelliguillaume opened 1 year ago

carelliguillaume commented 1 year ago

Bug Report

Capacitor Version

💊 Capacitor Doctor 💊

Latest Dependencies:

@capacitor/cli: 4.3.0 @capacitor/core: 4.3.0 @capacitor/android: 4.3.0 @capacitor/ios: 4.3.0

Installed Dependencies:

@capacitor/cli: 4.3.0 @capacitor/android: 4.3.0 @capacitor/ios: 4.3.0 @capacitor/core: 4.3.0

[success] iOS looking great! 👌

Platform(s)

iOS (tested on versions: 14, 15, 16)

Current Behavior

When I add the SceneDelegate iOS architecture (needed by Apple CarPlay), ‘appUrlOpen’ event provided by Capacitor App plugin stops working on iOS when App is opened from an URL for the first time. When the App is opened from an URL while the application is in background there is no problem. But when the app is killed and opened for the first time from an URL (URL Scheme or Universal Link) it doesn’t work.

We’ve found a dirty workaround, its a concurrency problem, and the function : "ApplicationDelegateProxy.shared.application(UIApplication.shared, open: url)" is called too early in the iOS SceneDelegate event triggered when the App is started from an URL: "func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {". When it’s called too early, the ApplicationDelegateProxy will not trigger the ‘appUrlOpen’ Capacitor App Plugin event. But when you delay the call for 0.5 or 1 seconds like I did in comments in SceneDelegate.swift in this sample you will see that the event will trigger with no problems.

When you add a SceneDelegate, the AppDelegate function triggered when application is opened from an URL will not be called :

Instead SceneDelegate events replace AppDelegate events with this function :

It works with AppDelegate architecture, but with SceneDelegate architecture, it seems to be called too early.

Expected Behavior

The ‘appUrlOpen’ event provided by Capacitor App should work on iOS when the App is opened from an URL (URL Scheme or Universal Link) with SceneDelegate iOS architecture.

Code Reproduction

https://github.com/carelliguillaume/ionic-capacitor-scenedelegate-openurl

This project is an Ionic / Capacitor App with just 1 tab to show the problem.

You just have to open the App from an URL Scheme defined is this sample starting with "ulys.alpha.auth://" with Safari. If the ‘appUrlOpen’ triggers, you will see an IonToast at startup with the URL and it will print also this URL in IonTextArea on the first tab.

IMG_6497

Other Technical Details

npm --version output: 9.6.6

node --version output: v14.17.6

pod --version output (iOS issues only): 1.11.2

Additional Context

•   iOS Devices used to reproduce the behavior
•   
•   iPhone 14 Pro (iOS 16)
•   iPhone X (iOS 15)
•   iPad Pro 1st Gen (iOS 14)
jcesarmobile commented 1 year ago

Hi, I've tested your sample app and I can't run it, it hangs on "waiting to attach to App". I don't have that problem with any other apps, so looks like there is something wrong with your sample app. Can you take a look or provide a new one?

But it's very likely that if the scene delegate method is called before App plugin is initalized, so the notification is fired before there is something listening to it and it get lost.

carelliguillaume commented 1 year ago

Hi, It's normal if it hangs on "Waiting to attach to App". It's an Xcode configuration to wait for the executable to be launched by the user on the device. With this configuration you can easily debug the App with breakpoints and launch it from an URL. The App is not launched directly when you click on start on Xcode. It's easier on this configuration to debug and show the problem.

Capture d’écran 2023-07-18 à 21 45 53 Capture d’écran 2023-07-18 à 21 45 33

Yes I think it's what you say, the method is called before the App Plugin init. That's why I delayed the call with this dirty timeout. And when it's delayed, the App plugin has time to be initialized. But I think we can find a clean way to wait for the App plugin to be initialized. Maybe we can "queue" this call while the App plugin is initialized. And when it's ok the App plugin can consume this "queued" call to not lose it.

tbajkacz commented 7 months ago

Having the same issue, any fix yet?

carelliguillaume commented 7 months ago

@jcesarmobile have you been able to reproduce the steps and launch the app ?

carelliguillaume commented 7 months ago

Having the same issue, any fix yet?

This issue was marked as "needs replay", but it was a mistake, you can reproduce easily with my program the problem, I explained how to debug with step by step, and explained what is the "Wait for the executable to be launched" and why it's used to easily reproduce this bug. But I didn't have any answers since Jul 18 2023.

tbajkacz commented 7 months ago

Would be nice to get a response from the team so that we know if there is a better workaround, or if it's going to be fixed soon.