Initial Steps
If you haven't done so already, create a new project in the Firebase console.
Click on "Add Firebase to your Android app" and follow the setup steps.
When prompted, enter your app's package name, for example,
com.android.myapp
At the end, you'll download a google-services.json file. You can download this file again at any time.
If you haven't done so already, copy this into your project's module folder, typically
app/
.In the Firebase console, enable Dynamic Links for your project.
Once Dynamic Links are enabled, you can create new Dynamic Links.
Add Firebase Dynamic Links to your app
Add the dependency for Dynamic Links to your app/build.gradle
file:
dependencies {
// ...
// For Java (Works for Kotlin as well)
implementation 'com.google.firebase:firebase-dynamic-links:20.1.1'
// Specifically For Kotlin
implementation 'com.google.firebase:firebase-dynamic-links-ktx:20.1.1'
}
Then sync your project.
Setting up the manifest
<activity
android:name="com.android.myapp.SplashActivity"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="mydomain.page.link"/>
<data android:scheme="http" android:host="mydomain.page.link"/>
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
SplashActivity
is the activity that handles the links. This XML code has an intent-filter
that's used in an Android app's manifest file. It tells the Android system that your app wants to respond to a certain type of intent. Here's what each part does:
<intent-filter android:autoVerify="true">
: Starts the intent filter. Theandroid:autoVerify="true"
attribute tells the Android system to verify whether the links being opened belong to your app or not.<action android:name="android.intent.action.VIEW" />
: This line says that your app wants to respond toVIEW
intents. AVIEW
intent is typically used to ask an app to display some data, such as a web page.<category android:name="android.intent.category.DEFAULT" />
: This line is required for your app to receive implicit intents (intents that don’t specify a specific app).<category android:name="android.intent.category.BROWSABLE" />
: This line is required for the link to be accessible from a web browser without the user having to explicitly open it in your app.The
<data>
elements specify the type of data your app wants to respond to. In this case, it’s saying that your app wants to respond when these specific URLs are opened:https://mydomain.page.link
http://mydomain.page.link
So, if any of these URLs are opened, and if your app is installed on the device, then your app will be considered as a candidate to handle the intent. But they are by default disabled under app settings' supported web addresses. We can make it enabled. Here's how
Enable supported web addresses by default
Firebase automatically uploads the assetlinks.json. But you must add the SHA256 fingerprint for the Android app. For release, you will need to add Play Store SHA256 signing keys. You can find the Play Store SHA256 signing keys under the Play Console developer account under Release > Setup > App Integrity. and then select your app as the handler for the dynamic link in the Firebase dynamic links console.
Firebase will generate mydomain.page.link/.well-known/assetlinks.json
It will take up to 2 hours for this file to be updated.
The content of this file will be like below
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "com.android.myapp",
"sha256_cert_fingerprints": [
"8D:9:E0:87:A7:DA:A0:C4:14:F5:F2:C2:E3:08:C3:EC:96:F8:B8:6A:18:67:B2:9A:27:95:93:C0:72:A7:C1:87"
]
}
}
]
After that, the switch to toggle the supported web address http://mydomain.page.link
on or off will disappear. This indicates that the address is permanently enabled.
Receive Dynamic Links in your app
Override the onNewIntent()
method in your main activity. This method gets called when an intent is set on an activity that is already running in the current task.
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
In Kotlin
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
}
The onNewIntent()
method is part of the Activity
lifecycle in Android. It’s called when an instance of an activity is brought to the foreground (made visible to the user). This can happen either because a new instance of an activity is being created, or because an existing one is being brought to the foreground.
When you override the onNewIntent()
method in your main activity, you’re telling your app what to do when it receives a new intent while it’s already running. In the context of Firebase Dynamic Links, this is where you would handle the incoming deep link.
setIntent(intent);
This line updates the original intent that started the activity with the new intent. This is useful in cases where you want to update the data being used by the activity.
By doing this, your app can handle dynamic links even when it’s already running and in the foreground. When a user clicks on a dynamic link, this method will be triggered, allowing your app to react accordingly.
Create Dynamic Links
You can create dynamic links in the Firebase console or programmatically. You can use these helper classes
In Java
package com.android.myapp;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import com.google.firebase.dynamiclinks.ShortDynamicLink;
public class Links {
public static final String DOMAIN_URI_PREFIX = "https://mydomain.page.link";
public static class ListLink extends Links {
int listing;
int userId;
String title;
public ListLink(int listing, int userId, String title) {
this.listing = listing;
this.userId = userId;
this.title = title;
}
@Override
public String toLink() {
return "https://www.mydomain.com/?listing=" + listing + "&userId=" + userId + "&title=" + title;
}
}
public static class ProfileLink extends Links {
int user;
public ProfileLink(int user) {
this.user = user;
}
@Override
public String toLink() {
return "https://www.mydomain.com/?user=" + user;
}
}
public static class PostLink extends Links {
int postId;
public PostLink(int postId) {
this.postId = postId;
}
@Override
public String toLink() {
return "https://www.mydomain.com/?postId=" + postId;
}
}
public String toLink() {
return "";
}
public static void createShortLinkAndShare(final Context context, Links data, final ProgressBar progressBar) {
if (progressBar != null) progressBar.setVisibility(ProgressBar.VISIBLE);
String baseUrl = data.toLink();
FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse(baseUrl))
.setDomainUriPrefix(Links.DOMAIN_URI_PREFIX)
.buildShortDynamicLink()
.addOnSuccessListener(new OnSuccessListener<ShortDynamicLink>() {
@Override
public void onSuccess(ShortDynamicLink shortDynamicLink) {
if (progressBar != null) progressBar.setVisibility(ProgressBar.GONE);
Uri shortLink = shortDynamicLink.getShortLink();
if (shortLink != null)
shareLink(context, shortLink);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (progressBar != null) progressBar.setVisibility(ProgressBar.GONE);
// Show dialog with error message
}
});
}
private static void shareLink(Context context, Uri link) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, link.toString());
shareIntent.setType("text/plain");
context.startActivity(Intent.createChooser(shareIntent, "Share link using"));
}
public static void createShortLinkAndShare(Fragment fragment, Links data, ProgressBar progressBar) {
createShortLinkAndShare(fragment.requireActivity(), data, progressBar);
}
}
Usage
createShortLinkAndShare(this, new Links.ListLink(123, 456, "My Title"), progressBar);
In Kotlin
First, add the dependency
implementation "org.jetbrains.kotlin:kotlin-reflect:1.8.21"
package com.android.myapp
// These are the imports for your Android app
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.widget.ProgressBar
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks
import com.android.myapp.dialog // This is a custom dialog function from your app
import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberProperties
interface Links // This is an interface for your link data classes
const val DOMAIN_URI_PREFIX = "https://mydomain.page.link" // This is the prefix for your Firebase Dynamic Links
// These are data classes that implement the Links interface and represent different types of links in your app
data class ListLink(val listing: Int, val userId: Int, val title: String) : Links
data class ProfileLink(val user: Int) : Links
data class PostLink (val postId: Int): Links
// This function converts a Links object to a URL string
fun Links.toLink(): String {
val params = this::class.memberProperties.mapNotNull { prop ->
(prop as? KProperty1<Links, *>)?.let { "${it.name}=${it.get(this)}" }
}.joinToString("&")
return "https://www.mydomain.com/?$params"
}
// This function creates a short Dynamic Link and shares it using an Android share intent
fun Context.createShortLinkAndShare(data: Links, progressBar: ProgressBar? = null) {
progressBar?.isVisible = true // Show the progress bar while the link is being created
val baseUrl = data.toLink() // Convert the data to a URL string
FirebaseDynamicLinks.getInstance().createDynamicLink() // Start creating a Dynamic Link
.setLink(Uri.parse(baseUrl)) // Set the link parameter to the URL string
.setDomainUriPrefix(DOMAIN_URI_PREFIX) // Set the domain URI prefix to your Firebase Dynamic Links domain
.buildShortDynamicLink() // Build a short Dynamic Link
.addOnSuccessListener { result -> // Handle the success case
progressBar?.isVisible = false // Hide the progress bar when done
val shortLink = result.shortLink // Get the short Dynamic Link from the result
if (shortLink != null)
shareLink(shortLink) // Share the link if it's not null
}
.addOnFailureListener { exception -> // Handle the failure case
progressBar?.isVisible = false // Hide the progress bar when done
dialog { exception.localizedMessage } // Show a dialog with the error message
}
}
// This function shares a link using an Android share intent
private fun Context.shareLink(link: Uri) {
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND // Set the action to ACTION_SEND to send data to other apps
putExtra(Intent.EXTRA_TEXT, link.toString()) // Put the link in the intent as extra text data
type = "text/plain" // Set the type of data being sent (plain text)
}
startActivity(Intent.createChooser(shareIntent, "Share link using")) // Start a chooser activity to let the user pick an app to share with
}
// This function is a convenience function for fragments to create and share a short Dynamic Link
fun Fragment.createShortLinkAndShare(data: Links, progressBar: ProgressBar? = null) =
requireActivity().createShortLinkAndShare(data, progressBar)
Usage
In your fragment or activity
createShortLinkAndShare(PostLink(pid), progressbar)
Handle Dynamic Links
In Java
// If the app is opened by a firebase link
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();
}
if (deepLink != null) {
// Extract the query parameters from the deep link
// These parameters are defined in the Links data classes
// Assuming that these variables are already declared.
userId = deepLink.getQueryParameter("user");
listingId = Integer.parseInt(deepLink.getQueryParameter("listing"));
listTitle = deepLink.getQueryParameter("title");
listUserId = Integer.parseInt(deepLink.getQueryParameter("userId"));
postId = Integer.parseInt(deepLink.getQueryParameter("postId"));
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
e.printStackTrace();
// Handle the error case here
}
});
In Kotlin
//If the app is opened by a firebase link
Firebase.dynamicLinks
.getDynamicLink(intent)
.addOnSuccessListener(this) { pendingDynamicLinkData: PendingDynamicLinkData? ->
// Get deep link from result (may be null if no link is found)
var deepLink: Uri? = null
if (pendingDynamicLinkData != null) {
deepLink = pendingDynamicLinkData.link
}
deepLink?.let {
// Extract the query parameters from the deep link
// These parameters are defined in the Links data classes
// Assuming that these variables are already declared.
userId = it.getQueryParameter("user") ?: ""
listingId = it.getQueryParameter("listing")?.toInt() ?: 0
listTitle = it.getQueryParameter("title") ?: ""
listUserId = it.getQueryParameter("userId")?.toInt() ?: 0
postId = it.getQueryParameter("postId")?.toInt() ?: 0
}
}
.addOnFailureListener(this) { e -> e.printStackTrace() }