Skip to content

Commit 3f237a3

Browse files
authored
Add getUtmParameters api method to PendingDynamicLinkData (#2445)
Add getUtmParameters api method to PendingDynamicLinkData. This is new api method to provide utm parameters associated with a firebase dynamic link. Approved api review doc : https://docs.google.com/document/d/1NDBjiuCQEs3vnaPGfYKK2cdvJMIsJqukRtrZf8wsWCk iOS PR for the same : firebase/firebase-ios-sdk#7505
1 parent d4c30ec commit 3f237a3

File tree

5 files changed

+265
-0
lines changed

5 files changed

+265
-0
lines changed

firebase-dynamic-links/api.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ package com.google.firebase.dynamiclinks {
128128
method @Nullable public android.net.Uri getLink();
129129
method public int getMinimumAppVersion();
130130
method @Nullable public android.content.Intent getUpdateAppIntent(@NonNull android.content.Context);
131+
method @NonNull public android.os.Bundle getUtmParameters();
131132
}
132133

133134
public interface ShortDynamicLink {

firebase-dynamic-links/src/main/java/com/google/firebase/dynamiclinks/PendingDynamicLinkData.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
import com.google.android.gms.common.GooglePlayServicesUtil;
2626
import com.google.android.gms.common.util.DefaultClock;
2727
import com.google.firebase.dynamiclinks.internal.DynamicLinkData;
28+
import com.google.firebase.dynamiclinks.internal.DynamicLinkUTMParams;
2829

2930
/** Provides accessor methods to dynamic links data. */
3031
public class PendingDynamicLinkData {
3132

3233
private final DynamicLinkData dynamicLinkData;
34+
@Nullable private final DynamicLinkUTMParams dynamicLinkUTMParams;
3335

3436
/**
3537
* Create a dynamic link from parameters.
@@ -40,13 +42,15 @@ public class PendingDynamicLinkData {
4042
public PendingDynamicLinkData(DynamicLinkData dynamicLinkData) {
4143
if (dynamicLinkData == null) {
4244
this.dynamicLinkData = null;
45+
this.dynamicLinkUTMParams = null;
4346
return;
4447
}
4548
if (dynamicLinkData.getClickTimestamp() == 0L) {
4649
long now = DefaultClock.getInstance().currentTimeMillis();
4750
dynamicLinkData.setClickTimestamp(now);
4851
}
4952
this.dynamicLinkData = dynamicLinkData;
53+
this.dynamicLinkUTMParams = new DynamicLinkUTMParams(dynamicLinkData);
5054
}
5155

5256
/**
@@ -61,6 +65,7 @@ protected PendingDynamicLinkData(
6165
@Nullable String deepLink, int minVersion, long clickTimestamp, @Nullable Uri redirectUrl) {
6266
dynamicLinkData =
6367
new DynamicLinkData(null, deepLink, minVersion, clickTimestamp, null, redirectUrl);
68+
dynamicLinkUTMParams = new DynamicLinkUTMParams(dynamicLinkData);
6469
}
6570

6671
/**
@@ -100,6 +105,21 @@ public Uri getLink() {
100105
return null;
101106
}
102107

108+
/**
109+
* Return the {@link Bundle} which contains utm parameters associated with the firebase dynamic
110+
* link.
111+
*
112+
* @return Bundle of utm parameters associated with firebase dynamic link.
113+
*/
114+
@NonNull
115+
public Bundle getUtmParameters() {
116+
if (dynamicLinkUTMParams == null) {
117+
return Bundle.EMPTY;
118+
}
119+
120+
return dynamicLinkUTMParams.asBundle();
121+
}
122+
103123
/**
104124
* The minimum app version requested to process the dynamic link that can be compared directly
105125
* with {@link android.content.pm.PackageInfo#versionCode}. If the minimum version code is higher
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.dynamiclinks.internal;
16+
17+
import android.os.Bundle;
18+
import android.text.TextUtils;
19+
import androidx.annotation.NonNull;
20+
import androidx.annotation.VisibleForTesting;
21+
22+
/**
23+
* Class to extract UTM parameters from firebase dynamic link.
24+
*
25+
* @hide
26+
*/
27+
public class DynamicLinkUTMParams {
28+
29+
@VisibleForTesting public static final String KEY_CAMPAIGN_BUNDLE = "_cmp";
30+
@VisibleForTesting public static final String KEY_SCION_DATA_BUNDLE = "scionData";
31+
@VisibleForTesting public static final String KEY_MEDIUM = "medium";
32+
@VisibleForTesting public static final String KEY_SOURCE = "source";
33+
@VisibleForTesting public static final String KEY_CAMPAIGN = "campaign";
34+
35+
/** Key to retrieve utm_medium from utm params bundle returned by {@link #asBundle()} */
36+
public static final String KEY_UTM_MEDIUM = "utm_medium";
37+
/** Key to retrieve utm_source from utm params bundle returned by {@link #asBundle()} */
38+
public static final String KEY_UTM_SOURCE = "utm_source";
39+
/** Key to retrieve utm_campaign from utm params bundle returned by {@link #asBundle()} */
40+
public static final String KEY_UTM_CAMPAIGN = "utm_campaign";
41+
42+
private final DynamicLinkData dynamicLinkData;
43+
@NonNull private final Bundle utmParamsBundle;
44+
45+
public DynamicLinkUTMParams(DynamicLinkData dynamicLinkData) {
46+
this.dynamicLinkData = dynamicLinkData;
47+
this.utmParamsBundle = initUTMParamsBundle();
48+
}
49+
50+
@NonNull
51+
public Bundle asBundle() {
52+
return new Bundle(utmParamsBundle);
53+
}
54+
55+
private Bundle initUTMParamsBundle() {
56+
if (dynamicLinkData == null || dynamicLinkData.getExtensionBundle() == null) {
57+
return Bundle.EMPTY;
58+
}
59+
60+
Bundle scionBundle = dynamicLinkData.getExtensionBundle().getBundle(KEY_SCION_DATA_BUNDLE);
61+
62+
if (scionBundle == null) {
63+
return Bundle.EMPTY;
64+
}
65+
66+
Bundle campaignBundle = scionBundle.getBundle(KEY_CAMPAIGN_BUNDLE);
67+
if (campaignBundle == null) {
68+
return Bundle.EMPTY;
69+
}
70+
71+
Bundle bundle = new Bundle();
72+
checkAndAdd(KEY_MEDIUM, KEY_UTM_MEDIUM, campaignBundle, bundle);
73+
checkAndAdd(KEY_SOURCE, KEY_UTM_SOURCE, campaignBundle, bundle);
74+
checkAndAdd(KEY_CAMPAIGN, KEY_UTM_CAMPAIGN, campaignBundle, bundle);
75+
return bundle;
76+
}
77+
78+
/*
79+
* Checks and adds the value from source bundle to the destination bundle based on the source
80+
* key and destination key.
81+
*/
82+
private void checkAndAdd(
83+
@NonNull String sourceKey,
84+
@NonNull String destKey,
85+
@NonNull Bundle source,
86+
@NonNull Bundle dest) {
87+
String value = source.getString(sourceKey);
88+
if (!TextUtils.isEmpty(value)) {
89+
dest.putString(destKey, value);
90+
}
91+
}
92+
}

firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/PendingDynamicLinkDataTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static junit.framework.Assert.assertEquals;
1818
import static junit.framework.Assert.assertFalse;
1919
import static junit.framework.Assert.assertNotNull;
20+
import static junit.framework.Assert.assertNotSame;
2021
import static junit.framework.Assert.assertNull;
2122
import static org.mockito.ArgumentMatchers.any;
2223
import static org.mockito.ArgumentMatchers.anyInt;
@@ -30,6 +31,7 @@
3031
import android.net.Uri;
3132
import android.os.Bundle;
3233
import com.google.firebase.dynamiclinks.internal.DynamicLinkData;
34+
import com.google.firebase.dynamiclinks.internal.DynamicLinkUTMParams;
3335
import org.junit.Before;
3436
import org.junit.Test;
3537
import org.junit.runner.RunWith;
@@ -189,6 +191,39 @@ public void testGetUpdateAppIntent_NameNotFoundException() throws Exception {
189191
assertNull(intent);
190192
}
191193

194+
@Test
195+
public void testGetUtmParameters_WithEmptyUTMParams() {
196+
PendingDynamicLinkData pendingDynamicLinkData =
197+
new PendingDynamicLinkData(createDynamicLinkDataExtensions());
198+
assertNotNull(pendingDynamicLinkData.getUtmParameters());
199+
assertEquals(pendingDynamicLinkData.getUtmParameters().size(), 0);
200+
}
201+
202+
@Test
203+
public void testGetUtmParameters_WithNonEmptyUTMParams() {
204+
Bundle scionBundle = new Bundle();
205+
Bundle campaignBundle = new Bundle();
206+
scionBundle.putBundle(DynamicLinkUTMParams.KEY_CAMPAIGN_BUNDLE, campaignBundle);
207+
campaignBundle.putString(DynamicLinkUTMParams.KEY_MEDIUM, "m");
208+
campaignBundle.putString(DynamicLinkUTMParams.KEY_SOURCE, "s");
209+
campaignBundle.putString(DynamicLinkUTMParams.KEY_CAMPAIGN, "c");
210+
211+
DynamicLinkData dynamicLinkData = createDynamicLinkDataExtensions();
212+
dynamicLinkData
213+
.getExtensionBundle()
214+
.putBundle(DynamicLinkUTMParams.KEY_SCION_DATA_BUNDLE, scionBundle);
215+
PendingDynamicLinkData pendingDynamicLinkData = new PendingDynamicLinkData(dynamicLinkData);
216+
217+
Bundle utmParamsBundle = pendingDynamicLinkData.getUtmParameters();
218+
assertNotNull(utmParamsBundle);
219+
assertNotSame(utmParamsBundle.size(), 0);
220+
221+
// Comparing Utm params
222+
assertEquals(utmParamsBundle.getString(DynamicLinkUTMParams.KEY_UTM_MEDIUM), "m");
223+
assertEquals(utmParamsBundle.getString(DynamicLinkUTMParams.KEY_UTM_SOURCE), "s");
224+
assertEquals(utmParamsBundle.getString(DynamicLinkUTMParams.KEY_UTM_CAMPAIGN), "c");
225+
}
226+
192227
private DynamicLinkData createDynamicLinkData() {
193228
return new DynamicLinkData(
194229
DYNAMIC_LINK, DEEP_LINK, MINIMUM_VERSION, CLICK_TIMESTAMP, null, updateAppUri);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.dynamiclinks.internal;
16+
17+
import static junit.framework.Assert.assertEquals;
18+
import static junit.framework.Assert.assertFalse;
19+
import static junit.framework.Assert.assertNotNull;
20+
import static junit.framework.Assert.assertTrue;
21+
22+
import android.os.Bundle;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.robolectric.RobolectricTestRunner;
26+
27+
@RunWith(RobolectricTestRunner.class)
28+
public class DynamicLinkUTMParamsTest {
29+
30+
@Test
31+
public void testAsBundle_WithNullExtensions() {
32+
DynamicLinkUTMParams dynamicLinkUTMParams = new DynamicLinkUTMParams(getDynamicLinkData(null));
33+
assertNonNullEmptyBundle(dynamicLinkUTMParams.asBundle());
34+
}
35+
36+
@Test
37+
public void testAsBundle_WithExtensionsButNullScionBundle() {
38+
Bundle extensions = getExtensions();
39+
extensions.remove(DynamicLinkUTMParams.KEY_SCION_DATA_BUNDLE);
40+
DynamicLinkUTMParams dynamicLinkUTMParams =
41+
new DynamicLinkUTMParams(getDynamicLinkData(extensions));
42+
assertNonNullEmptyBundle(dynamicLinkUTMParams.asBundle());
43+
}
44+
45+
@Test
46+
public void testAsBundle_WithExtensionsButNullCampaignBundle() {
47+
Bundle extensions = getExtensions();
48+
extensions
49+
.getBundle(DynamicLinkUTMParams.KEY_SCION_DATA_BUNDLE)
50+
.remove(DynamicLinkUTMParams.KEY_CAMPAIGN_BUNDLE);
51+
DynamicLinkUTMParams dynamicLinkUTMParams =
52+
new DynamicLinkUTMParams(getDynamicLinkData(extensions));
53+
assertNonNullEmptyBundle(dynamicLinkUTMParams.asBundle());
54+
}
55+
56+
@Test
57+
public void testAsBundle_WithExtensionsButNullUtmParams() {
58+
DynamicLinkUTMParams dynamicLinkUTMParams =
59+
new DynamicLinkUTMParams(getDynamicLinkData(getExtensions()));
60+
assertNonNullEmptyBundle(dynamicLinkUTMParams.asBundle());
61+
}
62+
63+
@Test
64+
public void testAsBundle_WithExtensionsButEmptyUtmParams() {
65+
DynamicLinkUTMParams dynamicLinkUTMParams =
66+
new DynamicLinkUTMParams(getDynamicLinkData(getExtensions("", "", "")));
67+
assertNonNullEmptyBundle(dynamicLinkUTMParams.asBundle());
68+
}
69+
70+
@Test
71+
public void testAsBundle_WithExtensionsContainingUtmParams() {
72+
DynamicLinkUTMParams dynamicLinkUTMParams =
73+
new DynamicLinkUTMParams(getDynamicLinkData(getExtensions("m", "s", "c")));
74+
// Non empty check
75+
assertFalse(isEmptyBundle(dynamicLinkUTMParams.asBundle()));
76+
77+
// Comparing Utm params
78+
assertEquals(
79+
dynamicLinkUTMParams.asBundle().getString(DynamicLinkUTMParams.KEY_UTM_MEDIUM), "m");
80+
assertEquals(
81+
dynamicLinkUTMParams.asBundle().getString(DynamicLinkUTMParams.KEY_UTM_SOURCE), "s");
82+
assertEquals(
83+
dynamicLinkUTMParams.asBundle().getString(DynamicLinkUTMParams.KEY_UTM_CAMPAIGN), "c");
84+
}
85+
86+
private void assertNonNullEmptyBundle(Bundle bundle) {
87+
assertNotNull(bundle);
88+
assertTrue(isEmptyBundle(bundle));
89+
}
90+
91+
private boolean isEmptyBundle(Bundle bundle) {
92+
return bundle.size() == 0;
93+
}
94+
95+
private Bundle getExtensions() {
96+
return getExtensions(null, null, null);
97+
}
98+
99+
private Bundle getExtensions(String medium, String source, String campaign) {
100+
Bundle bundle = new Bundle();
101+
Bundle scionBundle = new Bundle();
102+
Bundle campaignBundle = new Bundle();
103+
104+
bundle.putBundle(DynamicLinkUTMParams.KEY_SCION_DATA_BUNDLE, scionBundle);
105+
scionBundle.putBundle(DynamicLinkUTMParams.KEY_CAMPAIGN_BUNDLE, campaignBundle);
106+
107+
campaignBundle.putString(DynamicLinkUTMParams.KEY_MEDIUM, medium);
108+
campaignBundle.putString(DynamicLinkUTMParams.KEY_SOURCE, source);
109+
campaignBundle.putString(DynamicLinkUTMParams.KEY_CAMPAIGN, campaign);
110+
111+
return bundle;
112+
}
113+
114+
private DynamicLinkData getDynamicLinkData(Bundle extensions) {
115+
return new DynamicLinkData(null, null, 0, 0L, extensions, null);
116+
}
117+
}

0 commit comments

Comments
 (0)