Flutterfire: [Dynamic Links] How to get query parameters from dynamic link?

Created on 30 Dec 2019  路  31Comments  路  Source: FirebaseExtended/flutterfire

Describe the bug
The documentation does not describe how to get a dynamic link URL or its query parameters. Attention! Dynamic link query parameters, not included deeplink!

crowd dynamic_links documentation enhancement

Most helpful comment

Same here. How to get query parameters from firebase dynamic link inside app?

https://testapp.page.link/ios?param=paramValue
How to get "paramValue"

All 31 comments

Same here. How to get query parameters from firebase dynamic link inside app?

https://testapp.page.link/ios?param=paramValue
How to get "paramValue"

Same here,

 final data = await FirebaseDynamicLinks.instance.getInitialLink();
 final Uri deepLink = data?.link;

when deepLink .hasQuery is always false

Any news on this?

You can do this. Where your query param is code :

final Uri deepLink = dynamicLink?.link;
deepLink.queryParameters['code']

The approach of @KingIdee is the correct one.

Example, following @karapetyan question:

Future handleDynamicLinks() async {

    // Get initial dynamic link if the app is started using the link
    final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();

    handleDeepLink(data);

    // Into foreground from dynamic link logic
    FirebaseDynamicLinks.instance.onLink(
      onSuccess: (PendingDynamicLinkData dynamicLinkData) async {
        handleDeepLink(dynamicLinkData);
      },
      onError: (OnLinkErrorException e){
        print('Dynamic Link Failed: $e');
      }
   );
}

void handleDeepLink(PendingDynamicLinkData data) {

         final Uri deepLink = data?.link;
         var paramValue = deepLink.queryParameters['paramValue'];

         if (deepLink != null) {
           print('deepLink detected: $deepLink');
           print('deepLink data: $paramValue');

         }         
 }

is it possible to pass dynamic query parameters instead of plain parameters? normally an application creates a token from backend and send a link to the email with a token, how can I pass that token to the dynamic link? right now I can get a query parameter if is defined in the console with ?parameter but no matter if my link has a value, in the console as the parameter has no value at all I get null, if I add in the console ?parameter=xxx I get xxx but, that's not the idea. so, anyone can please help me out to understand this, since the documentation has no enough information regarding this.

I face the same issue, the query parameters are lost during URL conversion.
I opened another ticket highlighting the issue:
https://github.com/FirebaseExtended/flutterfire/issues/3125

It's really bizarre that the e-mail templating system from Firebase auth is essentially incompatible with dynamic links.

In the Firebase docs here:
https://firebase.google.com/docs/dynamic-links/create-manually

It says:

Specify a URL that your app can handle, typically the app's content or payload, which initiates app-specific logic (such as crediting the user with a coupon or displaying a welcome screen). This link must be a well-formatted URL, be properly URL-encoded, use either HTTP or HTTPS, and cannot be another Dynamic Link.

Bolded section being key.

However, Firebase e-mail templating attaches the mode and code query parameterrs mode=<action>&oobCode=<code> without URL encoding anything. That means it's impossible to define the password reset link as a dynamic link by using something like this:

https://your_subdomain.page.link/?link=https%3A%2F%2Fyour.domain%2F__%2Fauth%2Faction%2F%3F

Because firebase will tack on the query parameters without URLEncoding them, resulting in a link that looks like:

https://your_subdomain.page.link/?link=https%3A%2F%2Fyour.domain%2F__%2Fauth%2Faction%2F%3F&mode=resetPassword&oobCode=9icrng4K_sp_MSbYg2onUghNyYDROiX2EQLTaRdz4bofAAF0DeRWzw&lang=en

Notice the ampersand & characters. By inserting a non-urlencoded ampersand at the end, those parameters simply "escape" from the link= query parameter and become parameters of the page.link instead.

Since the dynamic link system knows nothing about "oobCode" and other parameters, it will simply drop them, and the final link will miss the necessary context to complete the operation.

Any updates on this? I'm also facing the same issue.

You can use https://pub.dev/packages/uni_links. This will helps in getting the raw url having query params also. So you dont need to use flutter dynamic links package if you dont need the retrieving link data

You can use https://pub.dev/packages/uni_links. This will helps in getting the raw url having query params also. So you dont need to use flutter dynamic links package if you dont need the retrieving link data

Uni links is totally different use-case unrelated to this issue. This is about firebase dynamic links losing initial query parameters.

You can use https://pub.dev/packages/uni_links. This will helps in getting the raw url having query params also. So you dont need to use flutter dynamic links package if you dont need the retrieving link data

Uni links is totally different use-case unrelated to this issue. This is about firebase dynamic links losing initial query parameters.

Of course, this is not related to Firebase Dynamic Links, I just explained how to make the things work. Uni_links helped my project to achieve what I need that which cant be done with Dynamic links

You can use https://pub.dev/packages/uni_links. This will helps in getting the raw url having query params also. So you dont need to use flutter dynamic links package if you dont need the retrieving link data

Uni links is totally different use-case unrelated to this issue. This is about firebase dynamic links losing initial query parameters.

Of course, this is not related to Firebase Dynamic Links, I just explained how to make the things work. Uni_links helped my project to achieve what I need that which cant be done with Dynamic links

I鈥檓 happy it works for you an uni_links is great. It just is not a workaround for this issue you are commenting on.

Any updates on this?

SOLVED for me anyway
I have spent hours on this issue and finally decided to create the link programmatically to see if it made a difference, and it did!

The link I created manually which did not work was
https://iomoney2.page.link/?link=https://iomoney.web.app/#/?report=EXAMPLE&ibi=iOmoneyLite

In iOS Swift, calling DynamicLinks.dynamicLinks().handleUniversalLink returned https://iomoney.web.app and would lose my report=EXAMPLE parameter

When I create the link programmatically I get:

https://iomoney2.page.link/?link=https%3A%2F%2Fiomoney%2Eweb%2Eapp%2F%23%2F%3Freport%3DEXAMPLE&ibi=iOmoneyLite

When I pass this to handleUniversalLink I get https://iomoney.web.app/#/?report=EXAMPLE which is what I want

After trying many combinations, it seems the # sign and the = sign between report and EXAMPLE are the only two characters throwing it off. If I use %23 for # and %3D for = it works again with this:

https://iomoney2.page.link/?link=https://iomoney.web.app/%23/?report%3DEXAMPLE&ibi=iOmoneyLite

The problem is inside Firebase REST API, but can be fixed from the plugin as well.
The plugin does this REST call internally:

curl --request POST \
  --url 'https://firebasedynamiclinks.googleapis.com/v1/reopenAttribution?key={firebase_key}' \
  --header 'content-type: application/json' \
  --header 'x-ios-bundle-identifier: {bundle_identifier}' \
  --data '{
    "bundle_id": "{bundle_identifier}",
    "sdk_version": "4.0.8",
    "requestedLink": "https://subdomain.domain.com/path?param=123456"
}'

This call returns:

{
  "deepLink": "https://subdomain.domain.com/path",
  "resolvedLink": "https://subdomain.domain.com/?link=https://subdomain.domain.com/path&apn={bundle_identifier}&isi=1493910790&ibi={bundle_identifier}&st={st}&sd={sd}?&si={si}"
}

Then the URL sent back to Flutter is the URL got from the response from the deepLink field.
Notice how in the request we sent https://subdomain.domain.com/path?param=123456 and in the response we got back https://subdomain.domain.com/path. So Firebase backend removes ?param=123456. What can the Flutter plugin do is ignore the deepLink from response and send back to Dart the original requestedLink which also has the params.

This is what I noticed for iOS.
On Android the URL does not have the query parameters from the start, so I don't think we can make it work just from the Flutter plugin.

@iapicca what do you think?

@varunkumarmedam using uni_links on Android gives you the option to open the URL either via Chrome or your own app. If user opens via your own app, the query parameters are present, if they open it via Chrome we again lose the query parameters, so it's not a reliable solution. Did you find a fix for this issue?

@tudor07 thats a nice explanation I wanted to give. But fortunately uni_links also still not the best solution. But when I opened my app from whatsapp it works(dont works if app runs in background) its crazy but I too waiting for the perfect solution.

I noticed that short links work around this issue but I have other issues with them so for the time being I am modifying the url string in

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {

    var handled = false
    if userActivity.activityType == NSUserActivityTypeBrowsingWeb && userActivity.webpageURL != nil {
        let origStr = userActivity.webpageURL!.absoluteString
        // this is a hack for universal link to retain my parameters
        let url = URL(string: origStr.replacingOccurrences(of: "iomoney.web.app/#/?event=", with: "iomoney.web.app/%23/?event%3D"))
        if (url != nil) {
            handled = DynamicLinks.dynamicLinks().handleUniversalLink(url!) { (dynamicLink, error) in
                if (error == nil && dynamicLink != nil && dynamicLink!.url != nil) {
                    self.open(url: dynamicLink!.url!)
                }
                else {
                    print(error!)
                }
            }
        }
    }
    return handled

}

@caitcif hope you know, we are talking about flutter firebase dynamic links here...

@caitcif hope you know, we are talking about flutter firebase dynamic links here...

OK, I don't know the difference but this thread started with firebase dynamic links and the exact issue I am seeing too.

@caitcif how did you fix for Android?

@caitcif how did you fix for Android?

I don't have an Android version, just iOS and Web. But if you can replace the # and ? characters in the dynamic link with their escape codes before passing to handleUniversalLink it should work. See my original post:

The link I created manually which did not work was
https://iomoney2.page.link/?link=https://iomoney.web.app/#/?report=EXAMPLE&ibi=iOmoneyLite

In iOS Swift, calling DynamicLinks.dynamicLinks().handleUniversalLink returned https://iomoney.web.app and would lose my report=EXAMPLE parameter

When I create the link programmatically I get:

https://iomoney2.page.link/?link=https%3A%2F%2Fiomoney%2Eweb%2Eapp%2F%23%2F%3Freport%3DEXAMPLE&ibi=iOmoneyLite

When I pass this to handleUniversalLink I get https://iomoney.web.app/#/?report=EXAMPLE which is what I want

After trying many combinations, it seems the # sign and the = sign between report and EXAMPLE are the only two characters throwing it off. If I use %23 for # and %3D for = it works again with this:

https://iomoney2.page.link/?link=https://iomoney.web.app/%23/?report%3DEXAMPLE&ibi=iOmoneyLite

@caitcif how did you fix for Android?

I don't have an Android version, just iOS and Web. But if you can replace the # and ? characters in the dynamic link with their escape codes before passing to handleUniversalLink it should work. See my original post:

The link I created manually which did not work was
https://iomoney2.page.link/?link=https://iomoney.web.app/#/?report=EXAMPLE&ibi=iOmoneyLite

In iOS Swift, calling DynamicLinks.dynamicLinks().handleUniversalLink returned https://iomoney.web.app and would lose my report=EXAMPLE parameter

When I create the link programmatically I get:

https://iomoney2.page.link/?link=https%3A%2F%2Fiomoney%2Eweb%2Eapp%2F%23%2F%3Freport%3DEXAMPLE&ibi=iOmoneyLite

When I pass this to handleUniversalLink I get https://iomoney.web.app/#/?report=EXAMPLE which is what I want

After trying many combinations, it seems the # sign and the = sign between report and EXAMPLE are the only two characters throwing it off. If I use %23 for # and %3D for = it works again with this:

https://iomoney2.page.link/?link=https://iomoney.web.app/%23/?report%3DEXAMPLE&ibi=iOmoneyLite

But when I tried it in android it seems not working for me. But happy if it works in iOS.

Did it worked in android for anyone..?!

For everyone who's still looking for a way to do this:

  • Every dynamic link has 2 forms: a short and a long one. You NEED to use the long one [check your dynamic link in firebase console]
  • The long version of the dynamic link will look something like this:
    https://domain.page.link/?link=https://domain.com/coupon&apn=com.domain&efr=1
  • Parse the query params and re-construct the link such that your queries end up attached to the link query param. Example:
    https://domain.page.link/?link=https://domain.com/coupon?myquery=123&apn=com.domain&efr=1
    In other words, DO NOT DO THIS:
    https://domain.page.link/?link=https://domain.com/coupon&apn=com.domainl&efr=1&myquery=123
  • Send the link [including through Firebase Verification Emails]

I've tried this on web, and I can get the queries out of the url. I'm hopeful your library on ios and android can get the queries from the link as well.

  • Parse the query params and re-construct the link such that your queries end up attached to the link query param.

That's not always gonna work, sadly, if you are following an external redirect (like in most auth flows).

  • Parse the query params and re-construct the link such that your queries end up attached to the link query param.

That's not always gonna work, sadly, if you are following an external redirect (like in most auth flows).

Isn't this the job of the external redirector though? e.g. Configure the authentication provider to keep query params.
I don't think this is related to either the OP or even dynamic links in general.

Most auth flows have you set up a redirect url, that redirects back to the app. This part is static, as it is hosted by the external provider you want access to. They normally redirect to the given url, and then attach something like an access token as a query param.

My point was simply that if the above is the case, then it's not solvable with dynamic links as the query params are lost.

I ended up solving it by redirecting to a cloud function, which then grabs the query params, and then redirects to the dynamic link.

  • Parse the query params and re-construct the link such that your queries end up attached to the link query param.

That's not always gonna work, sadly, if you are following an external redirect (like in most auth flows).

Isn't this the job of the external redirector though? e.g. Configure the authentication provider to keep query params.
I don't think this is related to either the OP or even dynamic links in general.

No, it is the job of dynamic links to not lose incoming query parameters.

Dynamic Link
https://monadeo.page.link/github_auth?code=xxxxx

Converts to:

Observed:
https://monadeo-test.firebaseapp.com/__/auth/handler

Expected:
https://monadeo-test.firebaseapp.com/__/auth/handler?code=xxxxx

Try yourself to implement Github authentication for example and you鈥檒l see that it cannot work because of the above.

  • Parse the query params and re-construct the link such that your queries end up attached to the link query param.

That's not always gonna work, sadly, if you are following an external redirect (like in most auth flows).

Isn't this the job of the external redirector though? e.g. Configure the authentication provider to keep query params.
I don't think this is related to either the OP or even dynamic links in general.

No, it is the job of dynamic links to not lose incoming query parameters.

Dynamic Link
https://monadeo.page.link/github_auth?code=xxxxx

Converts to:

Observed:
https://monadeo-test.firebaseapp.com/__/auth/handler

Expected:
https://monadeo-test.firebaseapp.com/__/auth/handler?code=xxxxx

Try yourself to implement Github authentication for example and you鈥檒l see that it cannot work because of the above.

Yes Dynamic links failed to send query params. This is one the most awaiting feature for us 馃槙

Was this page helpful?
0 / 5 - 0 ratings