Programmatically generated dynamic links are not properly catched by
FirebaseDynamicLinks.instance.getInitialLink().
if the app is closed. However, if the app is open it is properly detected by the listener for new incoming dynamic links. It is not clear to me if it is a setup problem, how I generate the dynamic link.
To Reproduce
First set up Firebase for Flutter project as documented. Then to set up a dynamic link:
/// See also
/// https://firebase.google.com/docs/dynamic-links/use-cases/rewarded-referral
/// how to implement referral schemes using Firebase.
Future<ShortDynamicLink> buildDynamicLink(String userId) async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
final String packageName = packageInfo.packageName;
var androidParams = AndroidParameters(
packageName: packageInfo.packageName,
minimumVersion: Constants.androidVersion, // app version and not the Android OS version
);
var iosParams = IosParameters(
bundleId: packageInfo.packageName,
minimumVersion: Constants.iosVersion, // app version and not the iOS version
appStoreId: Constants.iosAppStoreId,
);
var socialMetaTagParams = SocialMetaTagParameters(
title: 'Referral Link',
description: 'Referred app signup',
);
var dynamicLinkParams = DynamicLinkParameters(
uriPrefix: 'https://xxxxxx.page.link',
link: Uri.parse('https://www.xxxxxxxxx${Constants.referralLinkPath}?${Constants.referralLinkParam}=$userId'),
androidParameters: androidParams,
iosParameters: iosParams,
socialMetaTagParameters: socialMetaTagParams,
);
return dynamicLinkParams.buildShortLink();
}
This dynamic link then can be shared with other new users.
I listen for initial links at app startup and then for new incoming links.
1) The link properly opens the app if the app is not running but the getInitialLink does not get it.
2) If the app is open the link is properly caught by the listener and all works.
Here is the very simple main.dart that I used to verify 1) that the initial link is not found with FirebaseDynamicLinks.instance.getInitialLink().
void main() async {
WidgetsFlutterBinding.ensureInitialized();
PendingDynamicLinkData linkData = await FirebaseDynamicLinks.instance.getInitialLink();
String link = linkData?.link.toString();
runApp(MyTestApp(link: link));
}
class MyTestApp extends StatelessWidget {
final String link;
MyTestApp({this.link});
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (BuildContext context, Widget child) {
return Scaffold(
body: Container(
child: Center(
child: Text('Initial dynamic Firebase link: $link')
),
),
);
}
);
}
}
Expected behavior
The link should open the app and trigger FirebaseDynamicLinks.instance.getInitialLink()..
Additional context
I (think I) properly configured Firebase project with Firebase console. I also verified that with 'signup by email link' and these dynamic links are working as expected, also when the app is not open.
* Additional Remark*
I should also note that the dynamic link opens the app if it is closed, the problem is that the getInitialLink function never returns the link.
Just for reference, this is the way I initialize Firestore dynamic link handling:
static Future<FirebaseDynamicLinkHandler> setup ({
@required AuthService auth,
@required UserDataService userDataService,
@required EmailSecureStore userCredentialsStorage,
}) async {
final linkHandler = FirebaseDynamicLinkHandler(
auth: auth,
userDataService: userDataService,
widgetsBinding: WidgetsBinding.instance,
emailStore: userCredentialsStorage,
);
// Check dynamic link once on app startup.
PendingDynamicLinkData linkData = await FirebaseDynamicLinks.instance.getInitialLink();
linkHandler._processDynamicLink(linkData?.link);
// Listen to subsequent links
FirebaseDynamicLinks.instance.onLink(
onSuccess: (linkData) {
return linkHandler._handleLink(linkData?.link);
},
// convert to PlatformException as OnLinkErrorCallback has private constructor and can't be tested
onError: (error) => linkHandler._handleLinkError(PlatformException(
code: error.code,
message: error.message,
details: error.details,
)),
);
return linkHandler;
}
Same here.
Hi Paoblo, this means you can confirm the behaviour that I see too?
Either we miss something in the config/setup or it is really a bug. Would be good to confirm.
when you set your intent. You need to set it to the link set in the firebase console to make it work. I closed the issue because I found 1 little inconspicuous line in the documentation on the firebase page that said you had to use your Dynamic Link domain. Not the deep link domain for your platform.
It should work then. So set that in your AndroidManifest.xml file if your doing it in android. I haven't tried IOS yet. But I imagine its something similar. getInitialLink doesn't return your Dynamic Link domain. It returns your deep link. So you won't have to reference your dynamic link domain.
I'm also facing this same issue. The issue is that FirebaseDynamicLinks.instance.getInitialLink() always capture the first link which opens the application. If the application is not opened via a dynamic link it will always return a null value.
Scenario 1:
The app is invoked via dynamic URL, getInitialLink() return the correct URL.
Scenario 2:
The app was in the background and it was resumed via dynamic URL, getInitialLink() returns null or previous record.
I fixed the issue via this code:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_retrieveDynamicLink();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_retrieveDynamicLink();
}
}
Future<void> _retrieveDynamicLink() async {
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData data) async {
final Uri deepLink = data?.link;
print(deepLink);
if (deepLink != null) {
print(deepLink.pathSegments);
List list = deepLink.pathSegments;
if (list != null && list.isNotEmpty) {
print(list.first);
}
}
}, onError: (OnLinkErrorException e) async {
print("onLinkError");
print(e.message);
});
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
Thanks @surveshoeb , your solution helped!
Most helpful comment
I fixed the issue via this code: