Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Share Your App Content Smoothly Using Firebase Dynamic Links

DZone's Guide to

Share Your App Content Smoothly Using Firebase Dynamic Links

Learn about using dynamic links with Firebase to let you share your app's content in a way that looks clean, and is all handled by Firebase and Android.

· Mobile Zone ·
Free Resource

Ready to go viral? How can you leverage free and existing technology to encourage organic downloads? Using a real-world example from my world famous Salad App, this tutorial will demonstrate how to utilize Firebase Dynamic Links in Kotlin to allow your users to seamlessly share content from your App.

As usual, all the source code for my Salad App is available on GitHub.

Sewing together the fabric of user experience is a dark and mysterious art. The digital pathways leading to your app must be as smooth and bug-free as the app itself if you want to minimize your bounce rate. The Holy Grail of user acquisition is organic growth via word of mouth, otherwise known as “going viral”. Nobody has successfully come up with a formula for going viral, but as an app craftsman, you can prepare your apps for the flood by making it easy and worthwhile for users to spread the word about how rad your product is.

User Story

Let's start this feature off properly by creating a mini User Centred Design persona.

Photo by Petr Sevcovic on Unsplash.

Meet Pete. Pete works in a butcher shop, and because he works all day with meat, he loves to eat salads at home.

Photo by NASA on Unsplash.

Meet Helga. Helga is Pete’s girlfriend and is an astronaut currently on a mission orbiting the earth. Since she has been living off protein bars and dehydrated ice cream for the past month, she is compiling a list of salads to eat as soon as she lands back on earth.

Good old Pete is carving up steaks, dreaming about salad, when he is notified at just the perfect moment about a new salad. He opens the world famous Salad App™ to find the salad of his dreams. His natural instinct is to share his excitement with his lovely wife Helga. As if the developer was psychic, a share button is right where it should be and Pete clicks it. He is presented with a share dialog giving him a list of apps with which to share it, he chooses SpaceBroadcastApp, clicks ‘share’ and sends a link to Helga.

Helga receives the link just as she is chewing through another tasteless vitamin jelly capsule. Overcome with excitement, she clicks on the link. Unfortunately, she is not yet privy to the wonders of the Salad App™ and when she clicks the link, instead of going straight into the app, she is taken to the Google Play Store. She installs the app and as soon as it has finished installing, is taken directly to the same screen that Pete was viewing when he clicked share. No login screen, no onboarding, no splash screen, just directly to the same screen Pete shared. She checks out the details of the salad and deciding Pete was right, saves it to her favorites…

This story can be broken into two parts:

  • Creating and sending the link and,
  • Decoding and interpreting the link.

Sending Pete's Details Screen

Basically, we just need to get the Salad Id from Pete's phone to Helga's phone. To do this, we wrap it up into a Uri as a Query Parameter.

    private fun createShareUri(saladId: String): Uri {
        val builder = Uri.Builder()
        builder.scheme(getString(R.string.config_scheme)) // "http"
                .authority(getString(R.string.config_host)) // "365salads.xyz"
                .appendPath(getString(R.string.config_path_salads)) // "salads"
                .appendQueryParameter(QUERY_PARAM_SALAD, saladId)
        return builder.build()
    }

The above code builds a URL that looks like this:

http://365salads.xyz/salads?saladId=-Kntip-_-etOntbIy5

Sharing this link 'as is' would be ok if we could assume that Helga was an Android user AND already has the app installed. These are some grotesque assumptions and this is where Firebase Dynamic Links takes over.

To get started with Firebase Dynamic Links, follow the install instructions and you will end up with a DYNAMIC_LINK_DOMAIN that looks something like:

abc1.app.goo.gl
    private fun createDynamicUri(myUri: Uri): Uri {
        val dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
                .setLink(myUri)
                .setDynamicLinkDomain(DYNAMIC_LINK_DOMAIN)
                .setAndroidParameters(DynamicLink.AndroidParameters.Builder().build())
//                .setIosParameters(DynamicLink.IosParameters.Builder("ibi").build())
                .buildDynamicLink()
        return dynamicLink.uri
    }

Notice that you can configure the behavior on both Android and iOS separately here with the DynamicLink Builders. Rad! This helps with the problem we face as app developers - that different versions of your app exist concurrently in the wild. Firebase gives you the option to fallback to say a mobile version of your website if the versioning criteria don't match... then there's iOS, but let's stick with the 101 version for now. iOS is a pain in the $&%§.

Now we have a link that looks something like this:

https://ude3d.app.goo.gl?apn=com.kan.salads.debug&link=http%3A%2F%2Fkan.com%2Fsalads%3Freferrer%3DSyPttFPc8AeV1Vwsyr2c1bF5Ej33%26saladId%3D-Kntip-SY0ZBoKhU8S2x

Ewwww. That looks like a dog's breakfast. If I received something like that from my girlfriend, I would assume that she'd been hacked. Luckily, Firebase has a shortening service that will reduce that Jane Austin novel into a Netflix TV Movie:

    private fun shortenLink(linkUri: Uri) {
        FirebaseDynamicLinks.getInstance().createDynamicLink()
                .setLongLink(linkUri)
                .buildShortDynamicLink()
                .addOnCompleteListener(this) { task ->
                    if (task.isSuccessful) {
                        val shortLink = task.result.shortLink
                        val msg = "Hey, check out this nutritious salad I found: $shortLink"
                        val sendIntent = Intent()
                        sendIntent.action = Intent.ACTION_SEND
                        sendIntent.putExtra(Intent.EXTRA_TEXT, msg)
                        sendIntent.type = "text/plain"
                        startActivity(sendIntent)
                    } else {
                        Timber.e(task.exception)
                    }
                }
    }


https://ude3d.app.goo.gl/O6KlJmSTg3HJov82

It does require an extra round trip, but it's worth it to give the impression that you have your s$%t together in 2018! Now we are ready to share!

Hey, check out this salad I found, https://ude3d.app.goo.gl/O6KlJmS2Tg3HJov82.

Receiving: Helga in Outer Space

Whether Helga has the app installed or not, it's all handled by Firebase and Android, you don't have to do anything special to get that magic happening.

You do, however, need to:

  1. Tell the Android Operating System what kind of (deep) links your app is capable of opening and;
  2. You do need to make sure that your Details Activity is able to be opened independently of any authorization or configuration that would normally take place in your launch activity.

Update Your Manifest File

The first step is done using a concept as old as time itself: Intent Filters, aka Deep Links. Using the AndroidManifest.xml file, you can specify an Activity to respond to a particular combination of broadcast parameters:

        <activity
            android:name=".activity.saladdetails.SaladDetailActivity"
            android:parentActivityName=".activity.home.HomeActivity"
            android:theme="@style/AppTheme.Details">
            <intent-filter android:label="@string/filter_view_http_salads">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="@string/config_host"
                    android:pathPrefix="/salads"
                    android:scheme="@string/config_scheme" />
                <!-- note that the leading "/" is required for pathPrefix-->
            </intent-filter>
        </activity>

In this case, the parameters are simple: scheme, host, and pathPrefix. Recognise these from when we created our original Uri on Pete's device?

    private fun createShareUri(saladId: String): Uri {
        val builder = Uri.Builder()
        builder.scheme(getString(R.string.config_scheme)) // "http"
                .authority(getString(R.string.config_host)) // "365salads.xyz"
                .appendPath(getString(R.string.config_path_salads)) // "salads"
                .appendQueryParameter(QUERY_PARAM_SALAD, saladId)
        return builder.build()
    }

The configuration of your AndroidManifest.xml and your Uri Builder must match.

This is where the DynamicLink Builders (mentioned above) for Android and iOS come in handy. If you happen to change your intent filters, or your change how they are built, you will break backward compatibility.

The above AndroidManifest.xml entry tells the OS that the app will respond to links in the form:

http://365salads.xyz/salads

by opening the SaladDetailsActivity.

Opening the Details Activity

The second step is to handle the incoming intent in the Activity. Once we are in the Details Activity, we first need to extract the Salad Id.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_details)
        
        FirebaseDynamicLinks.getInstance().getDynamicLink(intent).addOnFailureListener {
            // error
            Timber.e(it)
        }.addOnSuccessListener {
            // deep link
            val saladId = if (it == null) {
                args.saladId
            } else {
                it.link.getQueryParameter(QUERY_PARAM_SALAD)
            }
            init(saladId)
        }
    }

Firebase does all the heavy parsing of the intent, all you need to do is decode the original Uri that you built back on Pete's device, feed it into your presenter and Helga, thousands of kilometers away in the stratosphere, is looking at the same delicious salad as her man back down on earth!

Gotcha!

But wait! What if you, like me, did all the authorization in on your launch Activity? The first bug I encountered with this app, was that the user had not yet been logged in (as an anonymous user) and therefore couldn't access the salad database!

This is the first gotcha of deep links and the first click free policy (which I think is a great tool to get people to 'try before they buy'). I had to centralize this login logic and start to remove my assumptions about which activity was the first to be opened...

There are many other topics related to sharing with Firebase Dynamic Links: App Invites and referrals, external marketing links to optimize a first-time user’s experience, verifying your app and website to prevent others apps intercepting your deep links, ensuring links work on the browser and iOS and analyzing analytics associated with each link.

Ping me on Twitter @nshred and let me know what you would like to learn about next!

Topics:
mobile ,mobile app development ,firebase ,android

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}