奖励引荐

用户引荐是赢得新用户的最有效方法之一。您可以将动态链接与实时数据库Cloud Functions for Firebase 结合使用,通过向引荐者和受邀者提供成功引荐应用内奖励,鼓励用户邀请朋友使用您的应用。

主要优势

  • 通过提供激励,鼓励您的用户邀请朋友使用您的应用,从而加速增长。
  • 邀请链接跨平台保持有效性。
  • 第一次打开您的应用的新用户可享受您为其特别定制的首次运行体验。例如,您可以自动将其与邀请他们的朋友建立联系。
  • 视情况延迟给予奖励,即直到新用户完成一些入门性任务(如学习完教程)之后才给予奖励。

下面介绍如何开始使用这项功能。

设置 Firebase 和 Dynamic Links SDK

建立一个新的 Firebase 项目,并将 Dynamic Links SDK 安装到您的应用中。请分别参阅适用于 iOSAndroidC++Unity 的安装说明。安装 Dynamic Links SDK 后,Firebase 就能向应用传递有关动态链接的数据,包括在用户安装应用后传递数据。如果没有此 SDK,则应用无法将安装后的用户与安装前的点击关联在一起。

要创建邀请,请先创建可供受邀者打开以接受邀请的链接。然后,您可在邀请内容中加入此链接。当受邀者通过打开该链接安装您的应用时,他们可以享受专门定制的首次运行体验,包括收到应用内奖励。

此邀请链接是具有 link 参数值的动态链接,该参数值用于指示动态链接来自您现有的用户。

您可以使用很多方法为这些 link 参数的有效负载设置格式并将其与您的应用相关联。一种简单的方法是在查询参数中指定邀请者的用户帐号 ID,如下例所示:

https://mygame.example.com/?invitedby=SENDER_UID

然后,要创建适合加入到邀请中的动态链接,您可以使用 Dynamic Link Builder API:

iOS (Swift)

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
}

Android

FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String uid = user.getUid();
String link = "https://mygame.example.com/?invitedby=" + uid;
FirebaseDynamicLinks.getInstance().createDynamicLink()
        .setLink(Uri.parse(link))
        .setDynamicLinkDomain("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();
                // ...
            }
        });

发送邀请

由于您已创建了链接,现在可以将其加入邀请中。邀请可以是电子邮件、短信或任何其他媒介形式,具体取决于哪一种最适合您的应用和受众群体。

以下是发送电子邮件邀请的示例:

iOS (Swift)

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)

Android

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 商店来安装您的应用。然后,当他们第一次打开您的应用时,您可以检索您在动态链接中包含的引荐信息,并根据此信息来给予奖励。

通常情况下,您应仅在受邀者注册后才给予引荐奖励,甚至是在新用户完成某项任务之后才给予奖励。在奖励条件满足之前,您需要持续跟踪从动态链接获取的奖励信息。

要跟踪此信息,可采用的一种方式是让受邀者以匿名方式登录,并将相关数据存储在匿名帐号的实时数据库记录中。当受邀者注册且匿名帐号被转换为永久帐号时,新帐号将与原匿名帐号具有相同的 UID,因而可以访问奖励信息。

以下示例演示了如何在受邀者打开您的应用后保存引荐者的 UID:

iOS (Swift)

func application(_ app: UIApplication, open url: URL, options:
    [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
  if let isDynamicLink = DynamicLinks.dynamicLinks()?.shouldHandleDynamicLink(fromCustomSchemeURL: url),
      isDynamicLink {
    let dynamicLink = DynamicLinks.dynamicLinks()?.dynamicLink(fromCustomSchemeURL: url)
    return handleDynamicLink(dynamicLink)
  }
  // Handle incoming URL with other methods as necessary
  // ...
  return false
}

@available(iOS 8.0, *)
func application(_ application: UIApplication,
    continue userActivity: NSUserActivity,
    restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
  guard let dynamicLinks = DynamicLinks.dynamicLinks() else { return false }
  let handled = dynamicLinks.handleUniversalLink(userActivity.webpageURL!) { (dynamicLink, error) in
    if (dynamicLink != nil) && !(error != nil) {
      self.handleDynamicLink(dynamicLink)
    }
  }
  if !handled {
    // Handle incoming URL with other methods as necessary
    // ...
  }
  return handled
}

func handleDynamicLink(_ dynamicLink: DynamicLink?) -> Bool {
  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.
        }
      }
    }
  }
  return true
}

Android

@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 对象。以下是使用电子邮件地址和密码登录的示例:

iOS (Swift)

let credential = EmailAuthProvider.credential(withEmail: email, password: password)

Android

AuthCredential credential = EmailAuthProvider.getCredential(email, password);

然后,将此凭据与匿名帐号相关联:

iOS (Swift)

if let user = Auth.auth().currentUser {
  user.link(with: credential) { (user, error) in
    // Complete any post sign-up tasks here.
  }
}

Android

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 的成功侦听器中触发您在上一步中创建的函数:

iOS (Swift)

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())
    }
  }
}

Android

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;
            });
          }
        });
      }
    });

至此,引荐者和新用户都已获得了奖励。

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面