Firebase DynamicLinks + Realtime Database

A couple of days ago I was thinking about making a share button in order to share custom content that my users generated through my app. The idea is that the user who uses my app will generate random content and if they want , they can also share it with friends.

I started searching and reading about deep linking and I found Firebase Dynamic Links , after reading the documentation and seeing that this feature will help me build what I want I started at first creating a manual Dynamic Link in the Firebase console to open a custom Activity with a simple <Intent-filter>

If you don't already know about deep links, I suggest you to see this great video by Firebase about how it works

It was a success at first and I was really happy about it !! But then... I just realized that I would need a little more logic behind my requirement, because since the user can generate random content all the time, they can be constantly changing and generating random links to share, and I cant be doing links manually since I don't really know what those links will host inside.

I started searching and reading at StackOverflow and I didn't found out any question that responds my requirement. After a while researching I found a video by Todd Kerpelman

This video opened my mind on how to create dynamic links programmatically but I just needed a little step forward.

Now, as Todd shows in the video, you can generate every random url depending on the item you clicked on your View, and that's awesome ! But I just needed one tiny thing, to generate that link with random data embedded that the user may do with my app.

Two ideas came to my head

First one was just generating a looooooooooong loooooong link with all the data inside of it and then just parse the response by spliting all the link, but this was really a serious job because my user can share tons of LatLng to draw a polyline in my map. So after a few minutes this idea was not viable.

Second one was the hit on the jackpot !

Why I don't use the push keys from Firebase Realtime Database to generate my random links and inside those push keys I store all the data from what my users may share ?

This was awesome ! so with just a few characters I could:

1.- Have a shorter URL to generate my dynamic links
2.- Not needing to split a really long string
3.- So what I needed to do mainly was getting my pushKey from that link, for example: http://myawesomesite.com/shared_id=pushKey

Just by having that pushkey I have access to all the information below that key, and that information was the information that my users shared with my app to friends.

So, talk is cheap, lets go to the implementation of this 🙂

First you will need to import Firebase Dynamic Links

implementation 'com.google.firebase:firebase-dynamic-links:16.1.5'

Second you will need to select the activity you want to open when the link is clicked and define the <intent-filters> inside of it

AndroidManifest.xml

<activity
android:name="com.gaston.myapp.MainActivity"
android:label="@string/activity_title"
android:screenOrientation="portrait">

<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="myawesomeapp.com"
android:scheme="https"
android:pathPrefix="/shared_content"/>
</intent-filter>

Now, here I will explain how it works

the three parameters inside data will define your entire url, for example this host, scheme and pathPrefix will generate this url

https://myawesomeapp.com/shared_content

The <intent-filter> will just let your link open that activity when you click on it.

Now lets code all the logic to generate random url landings for each custom shared data that the user may want to share.

First, in the activity you will launch with the <intent-filter> , in this case my activity is MainActivity.class

Now , in order to let my users share content through my app to any friends I just implemented a little FloatingActionButton with the share image

activity_main.xml

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:backgroundTint="@color/white"
app:fabSize="mini"
android:backgroundTint="@color/colorPrimary"
android:layout_gravity="end"
android:tint="@color/white"
android:src="@drawable/ic_share_black_24dp"
android:layout_margin="8dp"
android:id="@+id/shareFab"/>

Here I just find my fab (FloatingActionButton) and call the method shareRecord(FloatingActionButton fab);

MainActivity.class

private FloatingActionButton shareFab;
shareFab = findViewById(R.id.shareFab);
shareRecord(shareFab);
/**
* Here after pressing my fab button I just generate my landing link with the random pushID and the data inside that ID
*
@param Share Fab Button
*/
private void shareRecord(FloatingActionButton fab) {

fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

final DatabaseReference pushReference = mDatabase.child("Records").push();

Map<String, Object> mapData = new HashMap<>();
mapData.put("trip_duration", duration);
mapData.put("totalDistance", distance);
mapData.put("pace", pace);
mapData.put("latlng", linkedLatLang);
pushReference.updateChildren(mapData).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
String pushKey = pushReference.getKey();
Log.d(TAG, "DeepLinkUrl: " + generateDeepLinkUrl(pushKey));

generateDynamicLink(generateDeepLinkUrl(pushKey));
} else {
Toast.makeText(MainActivity.this, getString(R.string.error_link), Toast.LENGTH_SHORT).show();
}


}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.e(TAG, "onFailure: " + e);
}
});


}
});
}

/**
* This will generate my link with the pushKey of the data stored above
*
@param pushID of the current set of data stored in Firebase Realtime Database
*
@return Returns a link that matches my AndroidManifest data block
*/
private String generateDeepLinkUrl(String pushID) {
return "https://myawesomeapp.com/shared_content=" + pushID;
}

Now, after generating my deep link I call generateDynamicLink() method, this will shrink the link returned by generateDeepLinkUrl()

generateDynamicLink(String url);

/**
* This will return a shrinked link using Firebase Dynamic Links , this method will shrink this lik myawesomeapp.com/shared_content=pushID
*
@param The url of the custom page we created above with the custom data of the user
*/
private void generateDynamicLink(String url) {

//Since this will take a little bit to generate I just make a simple dialog that is the same as a ProgressDialog displaying to the user a message that says that the link to share is beign generated

final Dialog dialog = new Dialog(this);
String generandoRecorrido = getString(R.string.generando_recorrido);
DialogsUtils.iniSaveDialog(dialog, generandoRecorrido);

//setDomainUriPrefix should host a link like this https://myawesomeapp.page.link , remember to use .page.link !!

//The androidParameters is just the package name of the app , this is because if the app is not installed it will prompt the user to the playstore to download it, package example com.gaston.myapp

FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse(url))
.setDomainUriPrefix(getString(R.string.page_link))
.setAndroidParameters(
new DynamicLink.AndroidParameters.Builder(getString(R.string.package_deeplink))
.setMinimumVersion(102)
.build())
.buildShortDynamicLink(ShortDynamicLink.Suffix.SHORT).addOnCompleteListener(RunnerMapsActivity.this, new OnCompleteListener<ShortDynamicLink>() {
@Override
public void onComplete(@NonNull Task<ShortDynamicLink> task) {

if (task.isSuccessful()) {
// we get the dynamic link generated and pass it to the shareDeepLink method
Uri shortURL = task.getResult().getShortLink();
Log.d(TAG, "ShortLink:" + shortURL);

dialog.dismiss();
shareDeepLink(shortURL.toString());
} else {
dialog.dismiss();
Toast.makeText(RunnerMapsActivity.this, getString(R.string.error_crear_link), Toast.LENGTH_SHORT).show();
}


}
});


}

Link output

https://myawesomeapp.page.link/Iv9K

This will be the link we will share with the user friends, now lets go to the latest method that just shares this link to a friend with all the data

/**
* We just share this link with any provider that the user may want
*
@param the short url generated by the method above
*/
private void shareDeepLink(String url) {

Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "Hey! check this content out " + url);
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Check this out !");
startActivity(Intent.createChooser(shareIntent, "Share this cool content"));

}

Awesome !! we are done uploading the custom data that the user may send to a friend, we generated the dynamic link and send it out to any friend with the provider they choose.

Now, we just need to receive that intent data when they click the link and open the app in order to fill the activity with the data that a friend sent to us.

This is very simple, we will create a method named getDynamicLink(FloatingActionButton shareFab); and we will call this method inside in our onCreate() , so, after the activity is launched it will check for the intent data of our link

/**
* The intent filter at our manifest launch this activity, and with this method we can get the data of that link, but we will need just the pushID of that link to retrieve the data, because we didnt store any data inside the link, but infact in the realtime database
*/
private void getDynamicLink(final FloatingActionButton shareFab) {
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent())
.addOnSuccessListener(this, new OnSuccessListener<PendingDynamicLinkData>() {
@Override
public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
// Get deep link from result (may be null if no link is found)
Uri deepLink = null;
if (pendingDynamicLinkData != null) {
deepLink = pendingDynamicLinkData.getLink();

Log.d(TAG, "Link obtenido del intent " + deepLink.getPath());

getAndParseSharedData(deepLink.getPath());
shareFab.setVisibility(View.GONE);


}


}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.w(TAG, "getDynamicLink:onFailure", e);
}
});
}

the method getAndParseSharedData(String url); needs the url of the link we opened, we can just get the path of were this link was generated , this will be like this https://myawesomeapp.com/shared_content=pushID , and the method getAndParseSharedData() will split that url, get the pushID, get the ata from Firebase Realtime Database and place it inside wherever we need it in our activity

/**
* We just parse the pushKey data to show to the user
*
@param the url with the pushKey as query parameter
*/
private void getAndParseSharedData(String url) {

final Dialog dialog = new Dialog(this);
DialogsUtils.iniSaveDialog(dialog,"Obteniendo información...");

String pushKey = "";
if (url.contains("-")) {
String[] parts = url.split("=");
pushKey = parts[1];
Log.d(TAG, "getAndParseSharedData: " + pushKey);
}

mDatabase.child("Recorridos").child(pushKey).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

LinkedList<LatLng> firebaseLatLng = new LinkedList<>();

if (dataSnapshot.exists()) {

//we get the data and update the view, for example updating a text view declared globally, remember, this is the data we push to the realtime database with the HashMap above when we generated the link, and now we are parsing it and showing it to the user who opened the link
mDistanceDataTextView.setText(String.valueOf(dataSnapshot.child("totalDistance").getValue();

//do the same for all the data you want to parse


}

@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.e(TAG, "onCancelled: "+databaseError );

}
});

}

After all of this , we are done ! hurray !

We just generated a custom landing link to share with our Firebase Realtime Database pushkey that has content inside of it, we short the link with Firebase Dynamic Links, we shared it and parse the data inside that link.

“First, solve the problem. Then, write the code.” – John Johnson