获得新用户的最有效方法之一是通过用户推荐。您可以将动态链接与实时数据库和Cloud Functions for Firebase一起使用,通过为推荐人和接收人的成功推荐提供应用内奖励来鼓励您的用户邀请他们的朋友。
主要优势
- 通过鼓励您的用户邀请他们的朋友来加速增长。
- 邀请链接跨平台工作。
- 首次打开您的应用程序的新用户可以获得您为他们定制的首次运行体验。例如,您可以自动将他们与邀请他们的朋友联系起来。
- 可选择延迟授予奖励,直到新用户完成一些介绍性任务,例如完成教程。
这是开始的方法!
设置 Firebase 和动态链接 SDK
设置一个新的 Firebase 项目并将动态链接 SDK 安装到您的应用中。 ( iOS 、 Android 、 C++ 、 Unity )。安装动态链接 SDK 允许 Firebase 将有关动态链接的数据传递给应用程序,包括在用户安装应用程序之后。如果没有 SDK,就无法将安装后用户与安装前点击联系起来。
创建邀请链接
要创建邀请,首先创建收件人打开以接受邀请的链接。稍后,您将在邀请文本中包含此链接。当邀请的接收者通过打开链接安装您的应用时,他们可以获得定制的首次运行体验,包括获得应用内奖励。
此邀请链接是一个动态链接,其link
参数值表明它来自您现有的用户。
您可以通过多种方式格式化这些link
参数有效负载并将它们绑定到您的应用程序中。一种简单的方法是在查询参数中指定发件人的用户帐户 ID,如下例所示:
https://mygame.example.com/?invitedby=SENDER_UID
然后,要创建适合包含在邀请中的动态链接,您可以使用 Dynamic Link Builder API:
迅速
guard let uid = Auth.auth().currentUser?.uid else { return }
let link = URL(string: "https://mygame.example.com/?invitedby=\(uid)")
let referralLink = DynamicLinkComponents(link: link!, domain: "example.page.link")
referralLink.iOSParameters = DynamicLinkIOSParameters(bundleID: "com.example.ios")
referralLink.iOSParameters?.minimumAppVersion = "1.0.1"
referralLink.iOSParameters?.appStoreID = "123456789"
referralLink.androidParameters = DynamicLinkAndroidParameters(packageName: "com.example.android")
referralLink.androidParameters?.minimumVersion = 125
referralLink.shorten { (shortURL, warnings, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.invitationUrl = shortURL
}
Kotlin+KTX
val user = Firebase.auth.currentUser!! val uid = user.uid val invitationLink = "https://mygame.example.com/?invitedby=$uid" Firebase.dynamicLinks.shortLinkAsync { link = Uri.parse(invitationLink) domainUriPrefix = "https://example.page.link" androidParameters("com.example.android") { minimumVersion = 125 } iosParameters("com.example.ios") { appStoreId = "123456789" minimumVersion = "1.0.1" } }.addOnSuccessListener { shortDynamicLink -> mInvitationUrl = shortDynamicLink.shortLink // ... }
Java
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); String uid = user.getUid(); String link = "https://mygame.example.com/?invitedby=" + uid; FirebaseDynamicLinks.getInstance().createDynamicLink() .setLink(Uri.parse(link)) .setDomainUriPrefix("https://example.page.link") .setAndroidParameters( new DynamicLink.AndroidParameters.Builder("com.example.android") .setMinimumVersion(125) .build()) .setIosParameters( new DynamicLink.IosParameters.Builder("com.example.ios") .setAppStoreId("123456789") .setMinimumVersion("1.0.1") .build()) .buildShortDynamicLink() .addOnSuccessListener(new OnSuccessListener<ShortDynamicLink>() { @Override public void onSuccess(ShortDynamicLink shortDynamicLink) { mInvitationUrl = shortDynamicLink.getShortLink(); // ... } });
发送邀请
现在您已经创建了链接,您可以将其包含在邀请中。邀请可以是电子邮件、SMS 消息或任何其他媒介,具体取决于最适合您的应用和受众的媒介。
例如,要发送电子邮件邀请:
迅速
guard let referrerName = Auth.auth().currentUser?.displayName else { return }
let subject = "\(referrerName) wants you to play MyExampleGame!"
let invitationLink = invitationUrl?.absoluteString
let msg = "<p>Let's play MyExampleGame together! Use my <a href=\"\(invitationLink)\">referrer link</a>!</p>"
if !MFMailComposeViewController.canSendMail() {
// Device can't send email
return
}
let mailer = MFMailComposeViewController()
mailer.mailComposeDelegate = self
mailer.setSubject(subject)
mailer.setMessageBody(msg, isHTML: true)
myView.present(mailer, animated: true, completion: nil)
Kotlin+KTX
val referrerName = Firebase.auth.currentUser?.displayName val subject = String.format("%s wants you to play MyExampleGame!", referrerName) val invitationLink = mInvitationUrl.toString() val msg = "Let's play MyExampleGame together! Use my referrer link: $invitationLink" val msgHtml = String.format("<p>Let's play MyExampleGame together! Use my " + "<a href=\"%s\">referrer link</a>!</p>", invitationLink) val intent = Intent(Intent.ACTION_SENDTO).apply { data = Uri.parse("mailto:") // only email apps should handle this putExtra(Intent.EXTRA_SUBJECT, subject) putExtra(Intent.EXTRA_TEXT, msg) putExtra(Intent.EXTRA_HTML_TEXT, msgHtml) } intent.resolveActivity(packageManager)?.let { startActivity(intent) }
Java
String referrerName = FirebaseAuth.getInstance().getCurrentUser().getDisplayName(); String subject = String.format("%s wants you to play MyExampleGame!", referrerName); String invitationLink = mInvitationUrl.toString(); String msg = "Let's play MyExampleGame together! Use my referrer link: " + invitationLink; String msgHtml = String.format("<p>Let's play MyExampleGame together! Use my " + "<a href=\"%s\">referrer link</a>!</p>", invitationLink); Intent intent = new Intent(Intent.ACTION_SENDTO); intent.setData(Uri.parse("mailto:")); // only email apps should handle this intent.putExtra(Intent.EXTRA_SUBJECT, subject); intent.putExtra(Intent.EXTRA_TEXT, msg); intent.putExtra(Intent.EXTRA_HTML_TEXT, msgHtml); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); }
在您的应用中检索推荐信息
当邀请收件人打开推荐链接时,他们将被定向到 App Store 或 Play Store 以安装您的应用程序(如果尚未安装)。然后,当他们第一次打开您的应用程序时,您可以检索包含在动态链接中的推荐信息并使用它来申请奖励。
通常,您希望仅在邀请收件人注册后或什至仅在新用户完成某些任务后才授予推荐奖励。在满足奖励标准之前,您需要跟踪从动态链接获得的奖励信息。
跟踪此信息的一种方法是匿名登录用户并将数据存储在匿名帐户的实时数据库记录中。当接收者注册并将匿名账户转换为永久账户时,新账户将与匿名账户具有相同的 UID,因此可以访问奖励信息。
例如,要在收件人打开您的应用程序后保存推荐人的 UID:
迅速
struct MyApplication: App {
var body: some Scene {
WindowGroup {
VStack {
Text("Example text")
}
.onOpenURL { url in
if DynamicLinks.dynamicLinks()?.shouldHandleDynamicLink(fromCustomSchemeURL: url) ?? false {
let dynamicLink = DynamicLinks.dynamicLinks()?.dynamicLink(fromCustomSchemeURL: url)
handleDynamicLink(dynamicLink)
}
// Handle incoming URL with other methods as necessary
// ...
}
}
}
}
func handleDynamicLink(_ dynamicLink: DynamicLink?) {
guard let dynamicLink = dynamicLink else { return false }
guard let deepLink = dynamicLink.url else { return false }
let queryItems = URLComponents(url: deepLink, resolvingAgainstBaseURL: true)?.queryItems
let invitedBy = queryItems?.filter({(item) in item.name == "invitedby"}).first?.value
let user = Auth.auth().currentUser
// If the user isn't signed in and the app was opened via an invitation
// link, sign in the user anonymously and record the referrer UID in the
// user's RTDB record.
if user == nil && invitedBy != nil {
Auth.auth().signInAnonymously() { (user, error) in
if let user = user {
let userRecord = Database.database().reference().child("users").child(user.uid)
userRecord.child("referred_by").setValue(invitedBy)
if dynamicLink.matchConfidence == .weak {
// If the Dynamic Link has a weak match confidence, it is possible
// that the current device isn't the same device on which the invitation
// link was originally opened. The way you handle this situation
// depends on your app, but in general, you should avoid exposing
// personal information, such as the referrer's email address, to
// the user.
}
}
}
}
}
Kotlin+KTX
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... Firebase.dynamicLinks .getDynamicLink(intent) .addOnSuccessListener(this) { pendingDynamicLinkData -> // Get deep link from result (may be null if no link is found) var deepLink: Uri? = null if (pendingDynamicLinkData != null) { deepLink = pendingDynamicLinkData.link } // // If the user isn't signed in and the pending Dynamic Link is // an invitation, sign in the user anonymously, and record the // referrer's UID. // val user = Firebase.auth.currentUser if (user == null && deepLink != null && deepLink.getBooleanQueryParameter("invitedby", false)) { val referrerUid = deepLink.getQueryParameter("invitedby") createAnonymousAccountWithReferrerInfo(referrerUid) } } } private fun createAnonymousAccountWithReferrerInfo(referrerUid: String?) { Firebase.auth .signInAnonymously() .addOnSuccessListener { // Keep track of the referrer in the RTDB. Database calls // will depend on the structure of your app's RTDB. val user = Firebase.auth.currentUser val userRecord = Firebase.database.reference .child("users") .child(user!!.uid) userRecord.child("referred_by").setValue(referrerUid) } }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... 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 the user isn't signed in and the pending Dynamic Link is // an invitation, sign in the user anonymously, and record the // referrer's UID. // FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); if (user == null && deepLink != null && deepLink.getBooleanQueryParameter("invitedby", false)) { String referrerUid = deepLink.getQueryParameter("invitedby"); createAnonymousAccountWithReferrerInfo(referrerUid); } } }); } private void createAnonymousAccountWithReferrerInfo(final String referrerUid) { FirebaseAuth.getInstance() .signInAnonymously() .addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { // Keep track of the referrer in the RTDB. Database calls // will depend on the structure of your app's RTDB. FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); DatabaseReference userRecord = FirebaseDatabase.getInstance().getReference() .child("users") .child(user.getUid()); userRecord.child("referred_by").setValue(referrerUid); } }); }
然后,当受邀人决定创建一个帐户时,您可以将匿名帐户中的推荐信息转移到受邀人的新帐户中。
首先,使用受邀者想要使用的登录方法获取AuthCredential
对象。例如,要使用电子邮件地址和密码登录:
迅速
let credential = EmailAuthProvider.credential(withEmail: email, password: password)
Kotlin+KTX
val credential = EmailAuthProvider.getCredential(email, password)
Java
AuthCredential credential = EmailAuthProvider.getCredential(email, password);
然后,将此凭据链接到匿名帐户:
迅速
if let user = Auth.auth().currentUser {
user.link(with: credential) { (user, error) in
// Complete any post sign-up tasks here.
}
}
Kotlin+KTX
Firebase.auth.currentUser!! .linkWithCredential(credential) .addOnSuccessListener { // Complete any post sign-up tasks here. }
Java
FirebaseAuth.getInstance().getCurrentUser() .linkWithCredential(credential) .addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { // Complete any post sign-up tasks here. } });
新的永久帐户可以访问您添加到匿名帐户的所有奖励数据。
向推荐人和收件人授予奖励
现在您已经从动态链接中检索并保存了邀请数据,只要满足您想要的条件,您就可以向推荐人和接收人授予推荐奖励。
尽管您可以从客户端应用程序写入实时数据库,但您通常希望仅允许从您的应用程序读取应用程序内货币等数据,并仅从后端执行写入操作。这个后端可以是任何能够运行 Firebase Admin SDK 的系统,但通常最容易使用 Cloud Functions 来执行这些任务。
例如,假设您有一款游戏,您希望在接收者注册后向接收者授予游戏币奖励,并在接收者达到 5 级后向推荐人授予游戏币奖励。
要授予注册奖励,请部署一个函数来监视要创建的特定实时数据库密钥,并在创建时授予奖励。例如:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.grantSignupReward = functions.database.ref('/users/{uid}/last_signin_at')
.onCreate(event => {
var uid = event.params.uid;
admin.database().ref(`users/${uid}/referred_by`)
.once('value').then(function(data) {
var referred_by_somebody = data.val();
if (referred_by_somebody) {
var moneyRef = admin.database()
.ref(`/users/${uid}/inventory/pieces_of_eight`);
moneyRef.transaction(function (current_value) {
return (current_value || 0) + 50;
});
}
});
});
然后,当新用户注册时,通过创建实时数据库密钥来触发此功能。例如,触发您在上一步中创建的linkWithCredential
的成功侦听器中的函数:
迅速
if let user = Auth.auth().currentUser {
user.link(with: credential) { (user, error) in
// Complete any post sign-up tasks here.
// Trigger the sign-up reward function by creating the "last_signin_at" field.
// (If this is a value you want to track, you would also update this field in
// the success listeners of your Firebase Authentication signIn calls.)
if let user = user {
let userRecord = Database.database().reference().child("users").child(user.uid)
userRecord.child("last_signin_at").setValue(ServerValue.timestamp())
}
}
}
Kotlin+KTX
Firebase.auth.currentUser!! .linkWithCredential(credential) .addOnSuccessListener { // Complete any post sign-up tasks here. // Trigger the sign-up reward function by creating the // "last_signin_at" field. (If this is a value you want to track, // you would also update this field in the success listeners of // your Firebase Authentication signIn calls.) val user = Firebase.auth.currentUser!! val userRecord = Firebase.database.reference .child("users") .child(user.uid) userRecord.child("last_signin_at").setValue(ServerValue.TIMESTAMP) }
Java
FirebaseAuth.getInstance().getCurrentUser() .linkWithCredential(credential) .addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { // Complete any post sign-up tasks here. // Trigger the sign-up reward function by creating the // "last_signin_at" field. (If this is a value you want to track, // you would also update this field in the success listeners of // your Firebase Authentication signIn calls.) FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); DatabaseReference userRecord = FirebaseDatabase.getInstance().getReference() .child("users") .child(user.getUid()); userRecord.child("last_signin_at").setValue(ServerValue.TIMESTAMP); } });
要在收件人达到第 5 级时向推荐人授予奖励,请部署一个函数来监视用户记录中level
字段的变化。如果用户从第 4 级升到第 5 级,并且用户记录了推荐人,则授予奖励:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.rewardReferrals = functions.database.ref('/users/{uid}/level')
.onUpdate(event => {
var level = event.data.val();
var prev_level = event.data.previous.val();
if (prev_level == 4 && level == 5) {
var referrerRef = event.data.ref.parent.child('referred_by');
return referrerRef.once('value').then(function(data) {
var referrerUid = data.val();
if (referrerUid) {
var moneyRef = admin.database()
.ref(`/users/${referrerUid}/inventory/pieces_of_eight`);
return moneyRef.transaction(function (current_value) {
return (current_value || 0) + 50;
});
}
});
}
});
推荐人和您的新用户现在都收到了他们的奖励。