Growing Your Android App With Firebase Invites
Firebase Invites provide a simple way to add user referral schemes to your app for free, without any additional resources. The system runs on top of Firebase Dynamic Links, and supports both email and SMS referrals.
Invite messages can be customised, and they can include custom data / deep links. This custom information works even if the user doesn’t have the app installed when they initially click the referral link, making Invites an excellent way to build your app’s user base.
This post is part of The Complete Guide to Firebase. Throughout this tutorial, the official documentation may be useful:
Implementation
As always, the entire Firebase Reference Project is open source, and there is a pull request for adding Firebase Invites if you just want to see the code changes required. This tutorial assumes you already have Firebase added to your project.
In this tutorial, you’ll learn how to add the ability for users to send out invite links, and identify if a user has come from an invite link.
Adding Firebase Invites to your project
First, visit the Dynamic Links tab in the Firebase console, and agree to the terms of service (if necessary). Don’t worry if there’s no terms of service to agree, it only occurs in some situations!
Next, add Firebase Invites by adding the following to your dependencies in your app-level build.gradle
file, then perform a Gradle sync:
implementation 'com.google.firebase:firebase-invites:16.0.5'
Sending invites
Displaying invite screen
The invite screen allows the user to customise the invite message, and select one or more email / SMS contacts. In the image below, you can see a user with SMS only (chat icon), email only (envelope icon), and both (envelope icon with arrow). Email addresses and phone numbers can also be manually entered.
To actually display this dialog, pass an AppInviteInvitation
to startActivityForResult()
, which can be customised using the builder. Only the dialog title and invitation message must be defined, the rest are optional.
private fun sendInviteOnClick() = activity!!
.startActivityForResult(
AppInviteInvitation.IntentBuilder("Share an invite!")
.setMessage("Here is the custom message inside the invitation!")
.setDeepLink(Uri.parse("https://firebasereference.jakelee.co.uk/deeplink"))
.setCustomImage(Uri.parse("https://via.placeholder.com/600x600/4286f4/000000?text=Invite+image!"))
.setCallToActionText("Accept invite")
.build(), INVITE_REQUEST_CODE)
setMessage
defines the text at the top of the invite dialog.setDeepLink
defines the deep link that should be retrieve when an invited user opens the app.setCustomImage
allows you to specify an image that should be sent along with email invites.setCallToActionText
allows you to specify the text on the invite button in the email. Note that during my implementation, this didn’t seem to have any effect.setEmailHtmlContent
andsetEmailSubject
can also be used to completely replace the email invitation.
INVITE_REQUEST_CODE
must be under ~32k, and identifies the result returned when the user closes the dialog.
Alerting user to sent invites
When the user closes the dialog, either due to successfully inviting other users or pressing back, onActivityResult
is called. This is called on your activity, even if you started the dialog from a fragment!
Once the requestCode
and resultCode
have been checked, the data
object can be passed to AppInviteInvitations
to get a list of invitation IDs. These IDs are useful for keeping track of which invites have been accepted, since they are also available when opening an invite link.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == InvitesFragment.INVITE_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
val ids = AppInviteInvitation.getInvitationIds(resultCode, data!!)
val idsString = ids.joinToString()
Toast.makeText(this, "Invited: $idsString", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(this, "Invite sending failed / cancelled: $resultCode", Toast.LENGTH_LONG).show()
}
}
}
Receiving invites
Text | |
---|---|
When a user clicks the dynamic invite link from an email or text, they are taken directly to your app (or to the Play Store to install your app). When this happens, you need to check with Firebase Dynamic Links if there are any unprocessed invitations. Note that this function returns success even if there are no new invites, the difference is in whether data
is null or not.
This logic should be included on every activity / fragment in your app where you want to check the user’s invite status, which is likely to be almost all.
private fun processPendingInvite() = FirebaseDynamicLinks.getInstance()
.getDynamicLink(activity!!.intent)
.addOnSuccessListener { data ->
if (data == null) {
Log.d("Invites", "getInvitation: no data")
} else {
val deepLink = data.link
val inviteId = FirebaseAppInvite.getInvitation(data).invitationId
Toast.makeText(activity!!, "Retrieved deep link of $deepLink and an inviteId of $inviteId", Toast.LENGTH_LONG).show()
}
}
.addOnFailureListener { Log.e("Invites", "Failed") }
Despite the documentation’s claims, invitations do not reset themselves once used! Once getDynamicLink
has returned an invitation, calling it again will return the same information. It is unknown if this is intentional, or a bug (version 16.0.5).
Additional notes
All SMS and Email invites use the user’s Google Play details. Whilst this is fine for SMS, emails are often sent to spam folders. Additionally, the partially customised email invites don’t seem to format very well. As such, using setEmailHtmlContent
and setEmailSubject
is recommended, to fully customise the invitation link.
Conclusion
Firebase Invites is a relatively simple to implement referral system, and whilst it does have a very limited feature set, it performs those features reliably. The best practices article provides a few useful tips, and there are two excellent simple implementations on the case studies page.
The basic referral system may be useful for simple apps, especially those where a user is likely to download & register for an app just to view a specific piece of content. However, a server should be used for management of these invite links, such as checking if an invite has been accepted. Surprisingly few games also use the feature, despite their dependence on referral & invite mechanics.
It’s also worth noting that for opening a related iOS app, setOtherPlatformsTargetApplication
must be used when displaying the invite dialog.