Mendapatkan pengguna baru dengan memberi reward atas rujukan pengguna

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 mengundang temannya dengan menawarkan reward dalam aplikasi untuk rujukan yang berhasil, baik bagi perujuk maupun penerima.

Manfaat utama

  • Mempercepat pertumbuhan dengan memberikan insentif agar pengguna mengundang teman-teman mereka.
  • Link undangan berfungsi 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 mengundang mereka.
  • 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 Link ke aplikasi, termasuk setelah pengguna menginstal aplikasi. Tanpa SDK ini, tidak ada cara untuk menghubungkan pengguna pascapenginstalan dengan klik prapenginstalan.

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

Link undangan ini adalah Dynamic Link berisi parameter value link yang menunjukkan bahwa link tersebut berasal dari pengguna 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 Link yang sesuai untuk dimasukkan ke dalam undangan, Anda dapat menggunakan Dynamic Link Builder API:

Swift

Catatan: Produk Firebase ini tidak tersedia di target macOS, Mac Catalyst, tvOS, atau watchOS.
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();
                // ...
            }
        });

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:

Swift

Catatan: Produk Firebase ini tidak tersedia di target macOS, Mac Catalyst, tvOS, atau watchOS.
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);
}

Mengambil informasi rujukan di aplikasi Anda

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

Sebaiknya Anda memberikan reward rujukan hanya setelah penerima undangan mendaftar atau bahkan hanya setelah pengguna baru menyelesaikan tugas tertentu. 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 datanya di arsip Realtime Database akun anonim tersebut. Saat penerima mendaftar dan akun anonim dikonversi menjadi akun permanen, akun baru tersebut akan mempunyai UID yang sama dengan akun anonim dan oleh karena itu dapat mengakses informasi reward.

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

Swift

Catatan: Produk Firebase ini tidak tersedia di target macOS, Mac Catalyst, tvOS, atau watchOS.
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);
                }
            });
}

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 menggunakan metode login yang ingin digunakan oleh penerima undangan. Misalnya, untuk login dengan alamat email dan sandi:

Swift

Catatan: Produk Firebase ini tidak tersedia di target macOS, Mac Catalyst, tvOS, atau watchOS.
let credential = EmailAuthProvider.credential(withEmail: email, password: password)

Kotlin+KTX

val credential = EmailAuthProvider.getCredential(email, password)

Java

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

Kemudian, hubungkan kredensial ini ke akun anonim:

Swift

Catatan: Produk Firebase ini tidak tersedia di target macOS, Mac Catalyst, tvOS, atau watchOS.
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.
            }
        });

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

Memberikan reward kepada perujuk dan penerima

Setelah mengambil dan menyimpan data undangan dari Dynamic Link, Anda dapat memberikan reward rujukan kepada perujuk dan penerima setiap kali kriteria yang Anda syaratkan terpenuhi.

Meskipun Anda dapat menulis ke Realtime Database dari aplikasi klien, sering kali Anda hanya ingin mengizinkan akses baca ke data tertentu, seperti mata uang dalam 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, misalnya Anda mempunyai game dan ingin memberikan reward berupa mata uang dalam game kepada penerima setelah ia mendaftar dan kepada perujuk setelah penerima mencapai level 5.

Untuk memberikan reward atas pendaftaran yang dilakukan, deploy fungsi yang memantau kunci Realtime Database tertentu yang akan dibuat dan memberikan reward setelah kunci tersebut 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 pemroses peristiwa sukses linkWithCredential yang Anda buat pada langkah sebelumnya:

Swift

Catatan: Produk Firebase ini tidak tersedia di target macOS, Mac Catalyst, tvOS, atau watchOS.
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);
            }
        });

Untuk memberikan reward kepada perujuk saat penerima mencapai level 5, deploy fungsi yang memantau perubahan pada kolom level di arsip pengguna. Jika pengguna naik level dari level 4 ke level 5 dan ia 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.