Skip to content

Commit 433a08e

Browse files
feat(dynamic_links): add additional longDynamicLink parameter for creating a short Dynamic Link enabling additional parameters to be appended such as "ofl". (#7796)
1 parent 8288b81 commit 433a08e

File tree

7 files changed

+193
-131
lines changed

7 files changed

+193
-131
lines changed

packages/firebase_dynamic_links/firebase_dynamic_links/android/src/main/java/io/flutter/plugins/firebase/dynamiclinks/FlutterFirebaseDynamicLinksPlugin.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ public void onMethodCall(MethodCall call, @NonNull final MethodChannel.Result re
133133
result.success(url);
134134
return;
135135
case "FirebaseDynamicLinks#buildShortLink":
136-
DynamicLink.Builder urlBuilder = setupParameters(call.arguments());
137-
methodCallTask = buildShortLink(urlBuilder, call.arguments());
136+
methodCallTask = buildShortLink(call.arguments());
138137
break;
139138
case "FirebaseDynamicLinks#getDynamicLink":
140139
case "FirebaseDynamicLinks#getInitialLink":
@@ -165,11 +164,17 @@ private String buildLink(Map<String, Object> arguments) {
165164
return urlBuilder.buildDynamicLink().getUri().toString();
166165
}
167166

168-
private Task<Map<String, Object>> buildShortLink(
169-
DynamicLink.Builder urlBuilder, @Nullable Map<String, Object> arguments) {
167+
private Task<Map<String, Object>> buildShortLink(@Nullable Map<String, Object> arguments) {
170168
return Tasks.call(
171169
cachedThreadPool,
172170
() -> {
171+
DynamicLink.Builder urlBuilder = setupParameters(arguments);
172+
String longDynamicLink = (String) arguments.get("longDynamicLink");
173+
174+
if (longDynamicLink != null) {
175+
urlBuilder.setLongLink(Uri.parse(longDynamicLink));
176+
}
177+
173178
Integer suffix = 1;
174179
Integer shortDynamicLinkPathLength = (Integer) arguments.get("shortLinkType");
175180
if (shortDynamicLinkPathLength != null) {
@@ -187,11 +192,8 @@ private Task<Map<String, Object>> buildShortLink(
187192

188193
Map<String, Object> result = new HashMap<>();
189194
ShortDynamicLink shortLink;
190-
if (suffix != null) {
191-
shortLink = Tasks.await(urlBuilder.buildShortDynamicLink(suffix));
192-
} else {
193-
shortLink = Tasks.await(urlBuilder.buildShortDynamicLink());
194-
}
195+
196+
shortLink = Tasks.await(urlBuilder.buildShortDynamicLink(suffix));
195197

196198
List<String> warnings = new ArrayList<>();
197199

packages/firebase_dynamic_links/firebase_dynamic_links/example/lib/main.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ class _MainScreenState extends State<_MainScreen> {
7777

7878
final DynamicLinkParameters parameters = DynamicLinkParameters(
7979
uriPrefix: 'https://reactnativefirebase.page.link',
80+
longDynamicLink: Uri.parse(
81+
'https://reactnativefirebase.page.link/?efr=0&ibi=io.invertase.testing&apn=io.flutter.plugins.firebase.dynamiclinksexample&imv=0&amv=0&link=https%3A%2F%2Ftest-app%2Fhelloworld&ofl=https://ofl-example.com',
82+
),
8083
link: Uri.parse(DynamicLink),
8184
androidParameters: const AndroidParameters(
8285
packageName: 'io.flutter.plugins.firebase.dynamiclinksexample',

packages/firebase_dynamic_links/firebase_dynamic_links/ios/Classes/FLTFirebaseDynamicLinksPlugin.m

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -158,24 +158,49 @@ - (void)buildLink:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResul
158158
}
159159

160160
- (void)buildShortLink:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result {
161-
FIRDynamicLinkComponents *components = [self setupParameters:arguments];
162-
163-
[components
164-
shortenWithCompletion:^(NSURL *_Nullable shortURL, NSArray<NSString *> *_Nullable warnings,
165-
NSError *_Nullable error) {
166-
if (error != nil) {
167-
result.error(nil, nil, nil, error);
168-
} else {
169-
if (warnings == nil) {
170-
warnings = [NSMutableArray array];
161+
FIRDynamicLinkComponentsOptions *options = [self setupOptions:arguments];
162+
NSString *longDynamicLink = arguments[@"longDynamicLink"];
163+
164+
if (longDynamicLink != nil) {
165+
NSURL *url = [NSURL URLWithString:longDynamicLink];
166+
[FIRDynamicLinkComponents
167+
shortenURL:url
168+
options:options
169+
completion:^(NSURL *_Nullable shortURL, NSArray<NSString *> *_Nullable warnings,
170+
NSError *_Nullable error) {
171+
if (error != nil) {
172+
result.error(nil, nil, nil, error);
173+
} else {
174+
if (warnings == nil) {
175+
warnings = [NSMutableArray array];
176+
}
177+
178+
result.success(@{
179+
kUrl : [shortURL absoluteString],
180+
@"warnings" : warnings,
181+
});
171182
}
172-
173-
result.success(@{
174-
kUrl : [shortURL absoluteString],
175-
@"warnings" : warnings,
176-
});
177-
}
178-
}];
183+
}];
184+
} else {
185+
FIRDynamicLinkComponents *components = [self setupParameters:arguments];
186+
components.options = options;
187+
[components
188+
shortenWithCompletion:^(NSURL *_Nullable shortURL, NSArray<NSString *> *_Nullable warnings,
189+
NSError *_Nullable error) {
190+
if (error != nil) {
191+
result.error(nil, nil, nil, error);
192+
} else {
193+
if (warnings == nil) {
194+
warnings = [NSMutableArray array];
195+
}
196+
197+
result.success(@{
198+
kUrl : [shortURL absoluteString],
199+
@"warnings" : warnings,
200+
});
201+
}
202+
}];
203+
}
179204
}
180205

181206
- (void)getInitialLink:(FLTFirebaseMethodCallResult *)result {

packages/firebase_dynamic_links/firebase_dynamic_links_platform_interface/lib/src/dynamic_link_parameters.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class DynamicLinkParameters {
1010
DynamicLinkParameters({
1111
required this.link,
1212
required this.uriPrefix,
13+
this.longDynamicLink,
1314
this.androidParameters,
1415
this.iosParameters,
1516
this.googleAnalyticsParameters,
@@ -52,11 +53,17 @@ class DynamicLinkParameters {
5253
/// Social Meta Tag parameters for a generated Dynamic Link URL.
5354
final SocialMetaTagParameters? socialMetaTagParameters;
5455

56+
/// Set the long Dynamic Link when building a short link (i.e. using `buildShortLink()` API). This allows the user to append
57+
/// additional query strings that would otherwise not be possible (e.g. "ofl" parameter). This will not work if using buildLink() API.
58+
final Uri? longDynamicLink;
59+
5560
/// Returns the current instance as a [Map].
5661
Map<String, dynamic> asMap() {
5762
return <String, dynamic>{
5863
'uriPrefix': uriPrefix,
5964
'link': link.toString(),
65+
if (longDynamicLink != null)
66+
'longDynamicLink': longDynamicLink.toString(),
6067
if (androidParameters != null)
6168
'androidParameters': androidParameters?.asMap(),
6269
if (googleAnalyticsParameters != null)
@@ -74,6 +81,6 @@ class DynamicLinkParameters {
7481

7582
@override
7683
String toString() {
77-
return '$DynamicLinkParameters($asMap)';
84+
return '$DynamicLinkParameters(${asMap()})';
7885
}
7986
}

packages/firebase_dynamic_links/firebase_dynamic_links_platform_interface/test/dynamic_link_parameters_test.dart

Lines changed: 111 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,16 @@ void main() {
4848

4949
String uriPrefix = 'https://';
5050

51+
const String oflLink = 'https://ofl-link.com';
52+
final longDynamicLink = Uri.parse(
53+
'https://reactnativefirebase.page.link?amv=0&apn=io.flutter.plugins.firebase.dynamiclinksexample&ibi=io.invertase.testing&imv=0&link=https%3A%2F%2Ftest-app%2Fhelloworld&ofl=$oflLink',
54+
);
55+
5156
group('$DynamicLinkParameters', () {
5257
DynamicLinkParameters dynamicLinkParams = DynamicLinkParameters(
5358
uriPrefix: uriPrefix,
5459
link: link,
60+
longDynamicLink: longDynamicLink,
5561
androidParameters: androidParams,
5662
googleAnalyticsParameters: googleParams,
5763
iosParameters: iosParams,
@@ -73,112 +79,116 @@ void main() {
7379
);
7480
expect(dynamicLinkParams.navigationInfoParameters, navigation);
7581
expect(dynamicLinkParams.socialMetaTagParameters, social);
82+
expect(dynamicLinkParams.longDynamicLink, longDynamicLink);
7683
});
84+
});
85+
group('asMap', () {
86+
test('returns the current instance as a [Map]', () {
87+
final result = dynamicLinkParams.asMap();
7788

78-
group('asMap', () {
79-
test('returns the current instance as a [Map]', () {
80-
final result = dynamicLinkParams.asMap();
81-
82-
expect(result, isA<Map<String, dynamic>>());
83-
expect(
84-
result['androidParameters']['fallbackUrl'],
85-
dynamicLinkParams.androidParameters?.fallbackUrl.toString(),
86-
);
87-
expect(
88-
result['androidParameters']['minimumVersion'],
89-
dynamicLinkParams.androidParameters?.minimumVersion,
90-
);
91-
expect(
92-
result['androidParameters']['packageName'],
93-
dynamicLinkParams.androidParameters?.packageName,
94-
);
95-
expect(result['uriPrefix'], dynamicLinkParams.uriPrefix);
96-
expect(
97-
result['googleAnalyticsParameters']['campaign'],
98-
dynamicLinkParams.googleAnalyticsParameters?.campaign,
99-
);
100-
expect(
101-
result['googleAnalyticsParameters']['content'],
102-
dynamicLinkParams.googleAnalyticsParameters?.content,
103-
);
104-
expect(
105-
result['googleAnalyticsParameters']['medium'],
106-
dynamicLinkParams.googleAnalyticsParameters?.medium,
107-
);
108-
expect(
109-
result['googleAnalyticsParameters']['source'],
110-
dynamicLinkParams.googleAnalyticsParameters?.source,
111-
);
112-
expect(
113-
result['googleAnalyticsParameters']['term'],
114-
dynamicLinkParams.googleAnalyticsParameters?.term,
115-
);
116-
expect(
117-
result['iosParameters']['appStoreId'],
118-
dynamicLinkParams.iosParameters?.appStoreId,
119-
);
120-
expect(
121-
result['iosParameters']['bundleId'],
122-
dynamicLinkParams.iosParameters?.bundleId,
123-
);
124-
expect(
125-
result['iosParameters']['customScheme'],
126-
dynamicLinkParams.iosParameters?.customScheme,
127-
);
128-
expect(
129-
result['iosParameters']['fallbackUrl'],
130-
dynamicLinkParams.iosParameters?.fallbackUrl.toString(),
131-
);
132-
expect(
133-
result['iosParameters']['ipadBundleId'],
134-
dynamicLinkParams.iosParameters?.ipadBundleId,
135-
);
136-
expect(
137-
result['iosParameters']['ipadFallbackUrl'],
138-
dynamicLinkParams.iosParameters?.ipadFallbackUrl.toString(),
139-
);
140-
expect(
141-
result['iosParameters']['minimumVersion'],
142-
dynamicLinkParams.iosParameters?.minimumVersion,
143-
);
144-
expect(
145-
result['itunesConnectAnalyticsParameters']['affiliateToken'],
146-
dynamicLinkParams.itunesConnectAnalyticsParameters?.affiliateToken,
147-
);
148-
expect(
149-
result['itunesConnectAnalyticsParameters']['providerToken'],
150-
dynamicLinkParams.itunesConnectAnalyticsParameters?.providerToken,
151-
);
152-
expect(
153-
result['itunesConnectAnalyticsParameters']['campaignToken'],
154-
dynamicLinkParams.itunesConnectAnalyticsParameters?.campaignToken,
155-
);
156-
expect(result['link'], dynamicLinkParams.link.toString());
157-
expect(
158-
result['navigationInfoParameters']['forcedRedirectEnabled'],
159-
dynamicLinkParams.navigationInfoParameters?.forcedRedirectEnabled,
160-
);
161-
expect(
162-
result['socialMetaTagParameters']['description'],
163-
dynamicLinkParams.socialMetaTagParameters?.description,
164-
);
165-
expect(
166-
result['socialMetaTagParameters']['imageUrl'],
167-
dynamicLinkParams.socialMetaTagParameters?.imageUrl.toString(),
168-
);
169-
expect(
170-
result['socialMetaTagParameters']['title'],
171-
dynamicLinkParams.socialMetaTagParameters?.title,
172-
);
173-
});
174-
});
175-
176-
test('toString', () {
89+
expect(result, isA<Map<String, dynamic>>());
90+
expect(
91+
result['androidParameters']['fallbackUrl'],
92+
dynamicLinkParams.androidParameters?.fallbackUrl.toString(),
93+
);
94+
expect(
95+
result['androidParameters']['minimumVersion'],
96+
dynamicLinkParams.androidParameters?.minimumVersion,
97+
);
98+
expect(
99+
result['androidParameters']['packageName'],
100+
dynamicLinkParams.androidParameters?.packageName,
101+
);
102+
expect(result['uriPrefix'], dynamicLinkParams.uriPrefix);
103+
expect(
104+
result['longDynamicLink'],
105+
dynamicLinkParams.longDynamicLink.toString(),
106+
);
107+
expect(
108+
result['googleAnalyticsParameters']['campaign'],
109+
dynamicLinkParams.googleAnalyticsParameters?.campaign,
110+
);
111+
expect(
112+
result['googleAnalyticsParameters']['content'],
113+
dynamicLinkParams.googleAnalyticsParameters?.content,
114+
);
115+
expect(
116+
result['googleAnalyticsParameters']['medium'],
117+
dynamicLinkParams.googleAnalyticsParameters?.medium,
118+
);
119+
expect(
120+
result['googleAnalyticsParameters']['source'],
121+
dynamicLinkParams.googleAnalyticsParameters?.source,
122+
);
123+
expect(
124+
result['googleAnalyticsParameters']['term'],
125+
dynamicLinkParams.googleAnalyticsParameters?.term,
126+
);
127+
expect(
128+
result['iosParameters']['appStoreId'],
129+
dynamicLinkParams.iosParameters?.appStoreId,
130+
);
177131
expect(
178-
dynamicLinkParams.toString(),
179-
equals('$DynamicLinkParameters(${dynamicLinkParams.asMap})'),
132+
result['iosParameters']['bundleId'],
133+
dynamicLinkParams.iosParameters?.bundleId,
134+
);
135+
expect(
136+
result['iosParameters']['customScheme'],
137+
dynamicLinkParams.iosParameters?.customScheme,
138+
);
139+
expect(
140+
result['iosParameters']['fallbackUrl'],
141+
dynamicLinkParams.iosParameters?.fallbackUrl.toString(),
142+
);
143+
expect(
144+
result['iosParameters']['ipadBundleId'],
145+
dynamicLinkParams.iosParameters?.ipadBundleId,
146+
);
147+
expect(
148+
result['iosParameters']['ipadFallbackUrl'],
149+
dynamicLinkParams.iosParameters?.ipadFallbackUrl.toString(),
150+
);
151+
expect(
152+
result['iosParameters']['minimumVersion'],
153+
dynamicLinkParams.iosParameters?.minimumVersion,
154+
);
155+
expect(
156+
result['itunesConnectAnalyticsParameters']['affiliateToken'],
157+
dynamicLinkParams.itunesConnectAnalyticsParameters?.affiliateToken,
158+
);
159+
expect(
160+
result['itunesConnectAnalyticsParameters']['providerToken'],
161+
dynamicLinkParams.itunesConnectAnalyticsParameters?.providerToken,
162+
);
163+
expect(
164+
result['itunesConnectAnalyticsParameters']['campaignToken'],
165+
dynamicLinkParams.itunesConnectAnalyticsParameters?.campaignToken,
166+
);
167+
expect(result['link'], dynamicLinkParams.link.toString());
168+
expect(
169+
result['navigationInfoParameters']['forcedRedirectEnabled'],
170+
dynamicLinkParams.navigationInfoParameters?.forcedRedirectEnabled,
171+
);
172+
expect(
173+
result['socialMetaTagParameters']['description'],
174+
dynamicLinkParams.socialMetaTagParameters?.description,
175+
);
176+
expect(
177+
result['socialMetaTagParameters']['imageUrl'],
178+
dynamicLinkParams.socialMetaTagParameters?.imageUrl.toString(),
179+
);
180+
expect(
181+
result['socialMetaTagParameters']['title'],
182+
dynamicLinkParams.socialMetaTagParameters?.title,
180183
);
181184
});
182185
});
186+
187+
test('toString', () {
188+
expect(
189+
dynamicLinkParams.toString(),
190+
equals('$DynamicLinkParameters(${dynamicLinkParams.asMap()})'),
191+
);
192+
});
183193
});
184194
}

0 commit comments

Comments
 (0)