Buka konsol

Memberikan reward kepada referral

Salah satu cara paling efektif untuk mendapatkan pengguna baru adalah melalui rujukan pengguna. Anda dapat menggunakan Dynamic Links bersama dengan Realtime Database dan Cloud Functions for Firebase untuk mendorong pengguna agar mengajak temannya dengan menawarkan reward dalam aplikasi untuk referral yang berhasil, baik bagi perujuk maupun penerima.

Manfaat utama

  • Mempercepat pertumbuhan dengan memberikan insentif agar pengguna mengundang teman-teman mereka.
  • Link undangan bekerja di semua platform.
  • Pengguna baru yang membuka aplikasi Anda untuk pertama kalinya mendapatkan pengalaman pertama yang disesuaikan bagi mereka. Misalnya, Anda dapat secara otomatis menghubungkan mereka dengan teman yang mengundangnya.
  • Secara opsional, menunda pemberian reward hingga pengguna baru menyelesaikan beberapa tugas dasar, seperti menyelesaikan tutorial.

Berikut cara memulainya.

Menyiapkan Firebase dan Dynamic Links SDK

Siapkan project Firebase baru dan instal Dynamic Links SDK ke dalam aplikasi Anda. (iOS, Android, C++, Unity). Dengan menginstal Dynamic Links SDK, Firebase dapat meneruskan data tentang Dynamic Links ke aplikasi, termasuk setelah pengguna menginstal aplikasi. Selain dengan SDK, tidak ada cara lain untuk menghubungkan pengguna yang telah menginstal dengan klik sebelum proses instal.

Untuk membuat undangan, pertama-tama buat link yang dapat dibuka penerima untuk menerima undangan. Kemudian, Anda akan memasukkan link ini ke teks undangan. Saat penerima undangan menginstal aplikasi Anda dengan membuka link, mereka akan mendapatkan pengalaman pertama yang disesuaikan, termasuk menerima reward dalam aplikasi.

Link undangan ini adalah Dynamic Links berisi parameter value link yang menunjukkan bahwa link ini berasal dari pengguna Anda yang sudah ada.

Ada banyak cara untuk memformat payload parameter link ini dan mengaitkannya ke aplikasi Anda. Salah satu caranya yang sederhana adalah dengan menetapkan ID akun pengguna milik pengirim dalam parameter kueri, seperti dalam contoh berikut:

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

Kemudian, untuk membuat Dynamic Links yang sesuai untuk dimasukkan ke dalam undangan, Anda dapat menggunakan Dynamic Links 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
}

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();
                // ...
            }
        });

Kotlin

val user = FirebaseAuth.getInstance().currentUser
val uid = user!!.uid
val link = "https://mygame.example.com/?invitedby=$uid"
FirebaseDynamicLinks.getInstance().createDynamicLink()
        .setLink(Uri.parse(link))
        .setDomainUriPrefix("https://example.page.link")
        .setAndroidParameters(
                DynamicLink.AndroidParameters.Builder("com.example.android")
                        .setMinimumVersion(125)
                        .build())
        .setIosParameters(
                DynamicLink.IosParameters.Builder("com.example.ios")
                        .setAppStoreId("123456789")
                        .setMinimumVersion("1.0.1")
                        .build())
        .buildShortDynamicLink()
        .addOnSuccessListener { shortDynamicLink ->
            mInvitationUrl = shortDynamicLink.shortLink
            // ...
        }

Mengirim undangan

Setelah link selesai dibuat, Anda dapat memasukkannya ke dalam undangan. Undangan dapat berupa email, pesan SMS, atau media lain, tergantung dari metode yang paling sesuai untuk aplikasi dan audience Anda.

Misalnya, untuk mengirim undangan email:

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)

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

Kotlin

val referrerName = FirebaseAuth.getInstance().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)
intent.data = 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(packageManager) != null) {
    startActivity(intent)
}

Mengambil informasi rujukan di aplikasi Anda

Setelah penerima undangan membuka link rujukan, mereka akan diarahkan ke App Store atau Play Store untuk menginstal aplikasi Anda jika belum terinstal. Kemudian, saat mereka membuka aplikasi Anda untuk pertama kalinya, Anda dapat mengambil informasi rujukan yang Anda masukkan ke Dynamic Links dan menggunakannya untuk menerapkan reward.

Biasanya, Anda ingin memberikan reward rujukan hanya setelah penerima undangan mendaftar atau hanya setelah pengguna baru menyelesaikan beberapa tugas. Hingga kriteria reward terpenuhi, Anda harus memantau informasi reward yang Anda peroleh dari Dynamic Link.

Salah satu cara untuk memantau informasi ini adalah dengan membuat pengguna login secara anonim dan menyimpan data di arsip Realtime Database akun anonim. Saat penerima mendaftar dan akun anonim dikonversi menjadi akun permanen, akun baru tersebut akan mempunyai UID yang sama dengan akun anonim dan dapat mengakses informasi reward.

Misalnya, untuk menyimpan UID perujuk setelah penerima membuka aplikasi Anda:

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
}

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

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // ...

    FirebaseDynamicLinks.getInstance()
            .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 = FirebaseAuth.getInstance().currentUser
                if (user == null &&
                        deepLink != null &&
                        deepLink.getBooleanQueryParameter("invitedby", false)) {
                    val referrerUid = deepLink.getQueryParameter("invitedby")
                    createAnonymousAccountWithReferrerInfo(referrerUid)
                }
            }
}

private fun createAnonymousAccountWithReferrerInfo(referrerUid: String?) {
    FirebaseAuth.getInstance()
            .signInAnonymously()
            .addOnSuccessListener {
                // Keep track of the referrer in the RTDB. Database calls
                // will depend on the structure of your app's RTDB.
                val user = FirebaseAuth.getInstance().currentUser
                val userRecord = FirebaseDatabase.getInstance().reference
                        .child("users")
                        .child(user!!.uid)
                userRecord.child("referred_by").setValue(referrerUid)
            }
}

Kemudian, saat penerima undangan memutuskan untuk membuat akun, Anda dapat mengalihkan informasi rujukan dari akun anonim ke akun baru penerima undangan.

Pertama-tama, ambil objek AuthCredential dengan menggunakan metode login yang ingin digunakan penerima undangan. Misalnya, login dengan alamat email dan sandi:

iOS (Swift)

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

Java

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

Kotlin

val credential = EmailAuthProvider.getCredential(email, password)

Kemudian, hubungkan kredensial ini ke akun anonim:

iOS (Swift)

if let user = Auth.auth().currentUser {
  user.link(with: credential) { (user, error) in
    // 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.
            }
        });

Kotlin

FirebaseAuth.getInstance().currentUser!!
        .linkWithCredential(credential)
        .addOnSuccessListener {
            // Complete any post sign-up tasks here.
        }

Akun baru yang permanen dapat mengakses semua data reward yang Anda tambahkan ke akun anonim.

Memberikan reward kepada perujuk dan penerima

Setelah Anda mengambil dan menyimpan data undangan dari Dynamic Links, Anda dapat memberikan reward rujukan kepada perujuk dan penerima kapan pun kriteria yang Anda syaratkan terpenuhi.

Meskipun Anda dapat menulis ke Realtime Database dari aplikasi klien, sering kali Anda ingin mengizinkan akses baca saja ke data tertentu, seperti uang dalam aplikasi dari aplikasi Anda, dan hanya menjalankan operasi tulis dari backend saja. Backend ini dapat berupa sistem apa pun yang mampu menjalankan Firebase Admin SDK, tetapi sering kali tugas ini lebih mudah dijalankan menggunakan Cloud Functions.

Sebagai contoh, anggaplah Anda mempunyai game dan ingin memberikan reward berupa uang dalam game kepada penerima setelah dia mendaftar dan kepada perujuk setelah penerima mencapai level 5.

Untuk memberikan reward atas pendaftaran, terapkan fungsi yang memantau kunci Realtime Database tertentu yang akan dibuat dan memberikan reward setelah kunci itu selesai dibuat. Misalnya:

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

Kemudian, saat pengguna baru mendaftar, picu fungsi ini dengan membuat kunci Realtime Database. Misalnya, picu fungsi di listener keberhasilan linkWithCredential yang Anda buat di langkah sebelumnya:

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

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

Kotlin

FirebaseAuth.getInstance().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 = FirebaseAuth.getInstance().currentUser
            val userRecord = FirebaseDatabase.getInstance().reference
                    .child("users")
                    .child(user!!.uid)
            userRecord.child("last_signin_at").setValue(ServerValue.TIMESTAMP)
        }

Untuk memberikan reward kepada perujuk saat penerima mencapai level 5, terapkan fungsi yang memantau perubahan pada kolom level di record pengguna. Jika pengguna naik level dari level 4 ke level 5 dan dia tercatat memiliki perujuk, berikan reward:

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

Perujuk dan pengguna baru Anda kini telah menerima reward.