firebase-ios-sdk icon indicating copy to clipboard operation
firebase-ios-sdk copied to clipboard

Dynamic Links (Universal links) on iOS13 not always working

Open danh-geo opened this issue 3 years ago • 17 comments

[REQUIRED] Step 1: Describe your environment

  • Xcode version: 11.6
  • Firebase SDK version: 6.28.1
  • Firebase Component: Dynamic Links
  • Component version: 6.28.1
  • Installation method: CocoaPods

[REQUIRED] Step 2: Describe the problem

Steps to reproduce:

Dynamic Links are not working consistently on iOS13. We have a number of our customers complaining about the issue and we've been able to replicate on a handful of our own devices here. For example, downloading our app store build we've seen the following: Not working: iPhone 7, 13.6.1 (via Gmail app) iPhone Xs, 13.3 (via Gmail app) iPhone XR, 13.6.1 (via Gmail app)

Working: iPhone SE, iOS 13.6.1 (via Gmail app) iPhone 6s, iOS 13.6 (via Gmail app) iPhone 6s Plus, 13.6.1 (via Mail app) iPhone 7, iOS 13.5.1 (via Gmail app) iPhone 6, iOS 12.4.8

I can't really pinpoint exact models/OS but it seems to be the more modern models are affected.

There is this related (but closed) issue: https://github.com/firebase/firebase-ios-sdk/issues/4914 where a number of users also experience the same issue, however no solution was provided. We have restarted the device, deleted/reinstalled the app etc, and problem always remains on the affected devices.

The symptom of the issue is that upon clicking the dynamic link from an email we send to the user, asking the user to verify their email address when creating an account, instead of the user being redirected to our app on the device, the user is presented with a preview.page.link web page with an “Open” button that directs the user to the app store even though the app is correctly installed on the device already.

See: image003

Note that we only use the long version of dynamic links (no short or “un-guessable” deeplink). We have tested tapping the dynamic link from gmail and outlook apps.

This is an example deeplink we use on our live app to verify a users email: https://{myapp}.page.link/?link=https%3A%2F%2Fverify.{mydomain}.com%2F%3FverificationToken%3DAAk6AqPrGAariuT23hcAWniAMmIraCpQuAt2IxZ1Edff4m8TtZYovfjMOGxuJyHB%26product%3Ddefault%26lang%3Den&ibi={ios_bundle_id}&isi={ios_app_id}&apn={android_pn}

As mentioned, for some users the OS correctly reopens our app for us to handle the link attribute. And for others, it shows a preview webpage.

We have verified the link is setup correctly by checking the debug flow diagram at:

https://{myapp}.page.link/?link=https%3A%2F%2Fverify.{mydomain}.com%2F%3FverificationToken%3DAAk6AqPrGAariuT23hcAWniAMmIraCpQuAt2IxZ1Edff4m8TtZYovfjMOGxuJyHB%26product%3Ddefault%26lang%3Den&ibi={ios_bundle_id}&isi={ios_app_id}&apn={android_pn}&d=1

See attached screenshots that shows 0 warnings and a complete flow diagram.

Screenshot 2020-09-02 at 12 32 28

We have also run the swift DynamicLinks.performDiagnostics(completion: nil) code

Which shows there are no issues:

---- Firebase Dynamic Links diagnostic output start ---- Firebase Dynamic Links framework version 4.2.0 System information: OS iOS, OS version 13.3, model iPhone Current date 2020-09-02 11:23:23 +0000 Device locale en-GB (raw en_GB), timezone Europe/Dublin Specified custom URL scheme is {ios_bundle_id} and Info.plist contains such scheme in CFBundleURLTypes key. AppID Prefix: {app_id_prefix}, Team ID: {team_id}, AppId Prefix equal to Team ID: YES performDiagnostic completed successfully! No errors found. ---- Firebase Dynamic Links diagnostic output end ----

And as mentioned already, we can see it works for some devices but not others. Android works as expected also.

We are using the firebase supplied domain.page.link domain so have no control over how the AASA file is served: https://{myapp}.page.link/apple-app-site-association Which shows:

{
   "applinks":{
      "apps":[
         
      ],
      "details":[
         {
            "appID":"<team_id>.<ios_bundle_id>",
            "paths":[
               "NOT /_/*",
               "/*"
            ]
         }
      ]
   }
}

During investigation, we found that, if we use the firebase “hosting” to set up a custom site we can force the use of a custom AASA file by creating a dummy hosted web page for our project which enables us to provide an AASA file, the issue does not reproduce. It opened the app correctly. Custom ASSA file: https://{myapp}.firebaseapp.com/apple-app-site-association

firebase.json on the hosting site:

{
  "hosting": {
    "site": "myapp",
    "appAssociation": "NONE",
    "public": "public",
    "rewrites": [
      {
        "source": "/**",
        "dynamicLinks": true
      }
    ],
    "headers": [
      {
        "source": "/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      }
    ]
  }
}

Even if that custom AASA file is identical to the default one (we checked by reading the AASA file directly from the default Firebase dynamic link URL: https://{myapp}.page.link/apple-app-site-association). The custom one works, and the default page.link doesn't

This however, is not a suitable solution as our systems are all set-up to use the default link already and we do not want an empty web page presence but there seems to be no other way to provide a custom AASA file for use by the Dynamic Links component of Firebase.

So the issue seems to be related to the default {myapp}.page.link setup / apple-app-site-association files auto generated by firebase when only enabling the dynamic link component of Firebase on iOS 13.

Hopefully thats enough information. I would be more than happy to provide any more information if it helps with the debugging. Many thanks in advance.

Relevant Code:

N/A

danh-geo avatar Sep 02 '20 11:09 danh-geo

I found a few problems with this issue:

  • I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
  • This issue does not seem to follow the issue template. Make sure you provide all the required information.

google-oss-bot avatar Sep 02 '20 11:09 google-oss-bot

Just to add some further testing we've tried.

I noticed you can add up to 10 url prefixs for the ____.page.link

So along with my current https://{myapp}.page.link I decided to create another called https://{myappalt}.page.link

Obviously both are in the same project, so when I view the ASSA files for both of these, they are identical.

I then updated my entitlements.plist to change applinks:myapp.page.link to applinks:myappalt.page.link

I also updated my deeplink to: https://{myappalt}.page.link/?link=https%3A%2F%2Fverify.{mydomain}.com%2F%3FverificationToken%3DAAk6AqPrGAariuT23hcAWniAMmIraCpQuAt2IxZ1Edff4m8TtZYovfjMOGxuJyHB%26product%3Ddefault%26lang%3Den&ibi={ios_bundle_id}&isi={ios_app_id}&apn={android_pn} (hence the same link as before, just changing the subdomain at the beginning)

I then tried again to see if it would open the app correctly. Unfortunately it still has the same issue. So creating a new url prefix didn't change/fix anything.

The only way I've got the dynamic link to work correctly on one of the affected devices is to within my firebase project, setup a new site within the "Hosting" area. For example I named my test site: myapptest

I made my firebase.json:

{
  "hosting": {
    "site": "myapptest",
    "appAssociation": "NONE",
    "public": "public",
    "rewrites": [
      {
        "source": "/.well-known/apple-app-site-association",
        "dynamicLinks": true,
        "destination": "/apple-app-site-association"
      },
      {
        "source": "/**",
        "dynamicLinks": true,
        "destination": "/index.html"
      }
    ],
    "headers": [
      {
        "source": "/.well-known/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      },
      {
        "source": "/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      }
    ]
  }
}

In my public folder I have: apple-app-site-association index.html

My apple-app-site-association is identical to the one that is created automatically for https://{myapp}.page.link/apple-app-site-association in that it shows:

{
   "applinks":{
      "apps":[
         
      ],
      "details":[
         {
            "appID":"<team_id>.<ios_bundle_id>",
            "paths":[
               "NOT /_/*",
               "/*"
            ]
         }
      ]
   }
}

With the exact same value for app id that the page.link example shows.

I made my index.html look like this:

<html>
<script type="text/javascript">
  var href = window.location.href;
  var url = new URL(href);
  var link = url.searchParams.get("link");
</script>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script type="text/javascript">
  try {
    new URL(link);
    document.write("<meta http-equiv=\"refresh\" content=\"0; URL=" + link + "\" />");
  } catch (_) {

  }
  </script>
  <title>Redirecting</title>
</head>
<body>
  <script type="text/javascript">
  try {
    new URL(link);
    document.write("<p>If you are not redirected, <a href=\"" + link + "\">click here</a>.</p>");
  } catch (_) {
    document.write("<p>Unable to redirect.</p>");
  }
  </script>
</body>
</html>

Obviously when tapping the dynamic link I expect the app to open and handle anyway. But in the off chance the link is tapped on desktop for example, I redirect to the url that I have as my "link" attribute of the dynamic link.

The last thing I did was update my xcode project.

I replaced the line in my entitlements file that had applinks:{myapp}.page.link with applinks:myapptest.firebaseapp.com

And I also added a new entry into my info.plist for:

<key>FirebaseDynamicLinksCustomDomains</key>
<array>
	<string>https://myapptest.firebaseapp.com</string>
</array>

I made sure to use the firebase deploy command to push my firebase hosting site to firebase: firebase deploy --only hosting -m "Testing dynamic links"

Now when I tap the link on one of the affected devices, it correctly redirected to my app.

I have no idea why using the "hosting" method worked, and not the "out of the box" page.link offered by firebase. I also don't know if my quick "hosting" test works for all devices as I only tested on a device I know has the issue.

Again using the "hosting" method above is currently NOT an option. Our app is live, and cloud systems and email templates all use the page.link solution. So I would like to understand what we need to do to get this working.

Thanks

danh-geo avatar Sep 03 '20 11:09 danh-geo

Hi @ryanwilson thanks for assigning @eldhosembabu I appreciate you will look at this issue once you get to it. However is there any chance you could provide an estimate of when you or someone might look into it? As mentioned we have a live app affecting our customers currently with this issue. Again I appreciate you have other issues/features to work on, but if you could provide an indication of when this issue will be investigated that would be very much appreciated. Thanks

danh-geo avatar Sep 03 '20 15:09 danh-geo

I'm facing the same issue, which was already reported and closed without any real solution. I also have a live app with firebase password-less email login, and this issue adds a ton of friction to it (and one star reviews).

Diagnostics:

---- Firebase Dynamic Links diagnostic output start ---- 
Firebase Dynamic Links framework version 4.0.8 
System information: OS iOS, OS version 13.6.1, model iPhone 
Current date 2020-09-03 19:07:01 +0000 
Device locale en-BR (raw en_BR), timezone America/ <REDACTED> 
Specified custom URL scheme is com. <REDACTED> and Info.plist contains such scheme in CFBundleURLTypes key. 
AppID Prefix:  <REDACTED>, Team ID: <REDACTED>, AppId Prefix equal to Team ID: YES 
performDiagnostic completed successfully! 
No errors found. 
---- Firebase Dynamic Links diagnostic output end ----

My last attempt to solve it was to implement the missing scene handlers for deepLinks (code below, objC), but that did not work. More info here.

- (void)scene:(UIScene *)scene
  willConnectToSession:(UISceneSession *)session
               options:(UISceneConnectionOptions *)connectionOptions {
    [[FIRDynamicLinks dynamicLinks]
      handleUniversalLink:[[connectionOptions.userActivities allObjects] firstObject].webpageURL
               completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) {
                 [self onDeepLinkResult:dynamicLink error:error];
               }];
}

- (void)scene:(UIScene *)scene
    openURLContexts:(NSSet<UIOpenURLContext *> *)urlContexts {
    [[FIRDynamicLinks dynamicLinks]
      handleUniversalLink:[[urlContexts allObjects] firstObject].URL
               completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) {
                 [self onDeepLinkResult:dynamicLink error:error];
               }];
}

- (void)scene:(UIScene *)scene
    continue:(NSUserActivity *)userActivity {
    [[FIRDynamicLinks dynamicLinks]
      handleUniversalLink:userActivity.webpageURL
               completion:^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) {
                 [self onDeepLinkResult:dynamicLink error:error];
               }];
} 

vinicius-animo avatar Sep 03 '20 20:09 vinicius-animo

@vinicius-animo Thanks for your feedback.

I can confirm I also tried the SceneDelegate implementation and it did NOT work either unfortunately. The affected devices still showed the same issue. I wasn't convinced it would make a difference anyway since we have a number of iOS 13 devices which work fine for our dynamic link, and some devices that don't. And as described above, on the affected devices I was able to confirm the dynamic link would work when using the "hosting" method. However its good to rule out.

Some other things I tried was:

  • Verify my URL scheme works. I use my bundle id as a URL scheme. So simply entering {bundle_id}:// into safari, did it open my app? Yes it did

  • For the "link" parameter I tried using different links such as google.com to see if that made any difference. It still had the same issue, showing the "preview" webpage.

  • I did the same test again ("link" parameter as google.com) but without any of the ibi, isi, apn parameters on the dynamic link. This time instead of showing the "preview" webpage, it went to google.com (the link attribute). So this behaviour at least seems consistent.

  • I did the same again as my last test, but instead using the actual "link" I wanted, but without the ibi, isi, apn parameters. Again it didn't show the "preview" webpage, and redirected to my link correctly. e.g. https://{myapp}.page.link/?link=https%3A%2F%2Fverify.{mydomain}.com%2F%3FverificationToken%3DAAk6AqPrGAariuT23hcAWniAMmIraCpQuAt2IxZ1Edff4m8TtZYovfjMOGxuJyHB%26product%3Ddefault%26lang%3Den

Of course, this isn't the behaviour I expect. I have the app installed and therefore expect the app to open.

danh-geo avatar Sep 04 '20 07:09 danh-geo

I'm having the same problem. Dynamic links worked fine a few days ago and now on the same devices the link will not open directly to the app but rather show the preview.page.link and then either go nowhere (in the case of email link signup) or go to the app store and not the app (in the case of my other dynamic links).

Edit: I tried deleting and recreating my dynamic link prefix thinking that might fix things. However when I try to recreate I get this error "Domain and path prefix are being released. Please retry in one month."

You HAVE GOT TO BE kidding me. This link is already built into the app. WTF.

Edit 2: After a bunch of finagling, things seem to be working again. I think things actually were ok and unchanged on Firebase's end. What got things working, I think, is some combination of updating Xcode and iOS and deleting the app and cleaning/deleting derived data on Xcode, restarting Xcode, and reinstalling the app.

Edit 3: Another key thing I discovered is that if you enter the dynamic link in safari, then you'll be taken to the preview page, but if you tap on it say in WhatsApp and things are configured correctly, it will go straight to the app. The behavior differs on click vs entering in Safari.

Also, another thing I changed was I was using a custom domain in the action url of the email template. I went back to the firebase default... this may have made a difference. I'm not sure what exactly was the key thing here to get things working again.

salami avatar Sep 07 '20 17:09 salami

Hi @salami,

Thanks for sharing your experience.

Like you we tried difference versions of Xcode, clear derived data etc, but the same affected devices always had the issue. We also have devices on the same iOS version using the same build, one device works, and the other not (see my original post).

One thing I found really interesting/weird just now is your suggestion of WhatsApp. Up until now we have been taping the dynamic link within an email using either the gmail app, outlook app or mail app depending on the device.

I pasted the link into WhatsApp and tried tapping it from there, and it redirected successfully to our app. So then I tried again tapping the link from gmail, and then suddenly that worked again as well. So then I thought I'd try deleting the app from the device, reinstall it again from the app store, and then try gmail again. And guess what? The error is back (shows the preview page). Now if I try tapping the link in WhatsApp again, it too also has the error. Any combination of deleting the app and tapping in either gmail or whatsapp still shows the error again. I have no idea why it worked very briefly on the first test. Also to note, the 3 devices we've managed to replicate the issue on was all tapping the dynamic link via the gmail app - not sure if this is related or not. But also keep in mind we have had many devices across different iOS versions that work fine with gmail. e.g. 13.6.1 using gmail, one device worked, and the other didn't. The only difference here being the model of iPhone.

danh-geo avatar Sep 09 '20 09:09 danh-geo

Thank god, with your solution:

<key>FirebaseDynamicLinksCustomDomains</key>
<array>
	<string>https://myapptest.firebaseapp.com</string>
</array>

I can fix the error Url is Nil and return google/link/?dismiss=1&is_weak_match=1

You saved my life sir @danh-geo it took me 20 hours already

hiepxanh avatar Sep 09 '20 13:09 hiepxanh

Hi @hiepxanh,

Are you using the "hosting" method of creating a {sitename}.firebaseapp.com as opposed to the {sitename}.page.link?

I'm still trying to use the {sitename}.page.link method of Firebase Dynamic Links, but I still have an issue with it on certain devices, even if I append dismiss=1&is_weak_match=1, e.g.:

https://{myapp}.page.link/?link=https%3A%2F%2Fverify.{mydomain}.com%2F%3FverificationToken%3DAAk6AqPrGAariuT23hcAWniAMmIraCpQuAt2IxZ1Edff4m8TtZYovfjMOGxuJyHB%26product%3Ddefault%26lang%3Den&ibi={ios_bundle_id}&isi={ios_app_id}&apn={android_pn}&dismiss=1&is_weak_match=1

From my understanding, you only need to use FirebaseDynamicLinksCustomDomains in the plist if its something other than {sitename}.page.link (I did try having {sitename}.page.link here also, but it made no difference in my tests. It was required for my {sitename}.firebaseapp.com test though)

The other thing I'm unclear on is dismiss=1&is_weak_match=1. I can't seem to find anything about this in the firebase documentation. Am I missing something?

I'm glad some of my findings helped you though 👍

danh-geo avatar Sep 10 '20 07:09 danh-geo

@danh-geo FYI, I switched libraries (now using branch.io SDK) and the problem is gone.

I'll keep following up the discussion here. Hope this bug is fixed soon :)

vinicius-animo avatar Sep 10 '20 13:09 vinicius-animo

Thanks @vinicius-animo, in the meantime we have removed the dynamic links from our email templates because of the unexpected/unpredictable behaviour.

Similar to my peculiar WhatsApp test a few posts up. I also experienced more weird behaviour. So as well as our email verification dynamic link (via our verify.{mydomain}.com), we also have a similar dynamic link for the forgot password experience (recover.{mydomain}.com). Both dynamic links are very similar. So I tested the live app store build for this recover dynamic link on one of our affected devices and it redirected to the app correctly. I then tried the original email verification dynamic link and suddenly that worked OK also. I then deleted the app and reinstalled from the app store and this time tested the original email verification dynamic link first, and it showed the "preview" error. I then tried the forgot password dynamic link and then now that also shows the "preview" error. And once I get the preview error for this link style, I always get the error even after app restarts.

danh-geo avatar Sep 11 '20 16:09 danh-geo

hi guys,

I used resolveShortLink function to get around the issue, something like this


let linkHandled = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (link, error) in

            if let error = error {
                dLog("Error while handling link: \(error.localizedDescription)")
                return
            }

            if let dynamicLink = link, dynamicLink.url != nil {
                DeeplinkManager.shared.handleDynamicLink(dynamicLink)
            } else {
                DynamicLinks.dynamicLinks().resolveShortLink(incomingURL) { (link, error) in
                    guard let link = link,
                          let component = (URLComponents(url: link, resolvingAgainstBaseURL: true)?.queryItems?.first { $0.name == "deep_link_id" }),
                          let deeplink = component.value?.toURL   else {
                        return
                    }
                    DispatchQueue.main.async {
                        _ = DeeplinkManager.shared.handleDeeplink(deeplink)
                    }
                }
            }
        }

ababeel avatar Sep 20 '20 11:09 ababeel

According to this: https://developer.apple.com/forums/thread/123554?answerId=419087022#419087022

Apple prioritizes .com's differently than .links (at least in US). Could this explain why the original posters Firebase hosted version worked better than the .link URL? If so, perhaps that is the solve?

broksonic21 avatar Apr 01 '21 11:04 broksonic21

It seems you can remove this default page by configuration it in step 5 of your Dynamic Link. You can also do it manually by adding parameter efr=1 when creating your url : https://firebase.google.com/docs/dynamic-links/create-manually

AntoinePitel avatar May 27 '22 16:05 AntoinePitel

Is there still no solution on this one from Firebase? i could only see workarounds.

vikpande avatar Sep 13 '22 16:09 vikpande

After looking up firebase documentation and other stackoverflow options, we created a piece of code that helped to resolve this issue.

You need to add "FirebaseDynamicLinksCustomDomains" parameter in info.plist file.

Dynamical URL : https://yourapp.page.link/?link=https://yourapp.com/test=12345&isi=14602xxxxx&ibi=com.xxxx.yourapp

The important parameter in info.plist file :

<key>FirebaseDynamicLinksCustomDomains</key>
<array>
    <string>https://yourapp.com</string>
    <string>https://yourapp.com/link</string>
</array> 

If you have a production critical app which has this issue, do not hesitate to ask me for inputs. Hit me up at https://khushalbhalsod.nl.

bhalsodkhushal avatar Sep 15 '22 18:09 bhalsodkhushal

I had something similar happening to one of my users and it turned out they had somehow disabled universal links on their phone for the app.

This video at 8:20 covers how to fix it - the user has to long press the link and select to open via the app again to re-enable universal links. https://youtu.be/KLBjAg6HvG0?t=500

Not sure if this is the same problem as everyone else is having, but thought it worth posting in case it helps.

anni-tim avatar Dec 15 '22 01:12 anni-tim

Not sure if this is related as I've tried some of the steps; my issue is once I press "Open" on the preview page, it does go back into the app - but it stays on the home screen, and doesn't go to the ViewController that I noted it should open in the AppDelegate. The Dynamic link configuration printed in the console says 'No errors found', but none of the print statements in the dynamic link functions in the App Delegate appear. -----> Screenshot attached, "something" never shows up and all of the related handling of incoming Dynamic link functions (off screen and shown below what's pictured in the screenshot) don't seem to get executed as well. Screenshot 2023-01-24 at 4 39 10 PM

dondy1996 avatar Jan 24 '23 21:01 dondy1996

The Firebase Dynamic Links service will be shutdown on August 25, 2025. In the meantime, only critical or security issues will be fixed in the SDK.

More at https://firebase.google.com/support/dynamic-links-faq

paulb777 avatar Aug 22 '23 16:08 paulb777