获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

احصل على مستخدمين جدد من خلال مكافأة إحالات المستخدم

واحدة من أكثر الطرق فاعلية للحصول على مستخدمين جدد هي من خلال إحالات المستخدمين. يمكنك استخدام الروابط الديناميكية جنبًا إلى جنب مع Realtime Database و Cloud Functions لـ Firebase لتشجيع المستخدمين على دعوة أصدقائهم من خلال تقديم مكافآت داخل التطبيق للإحالات الناجحة لكل من المُحيل والمستلم.

الفوائد الرئيسية

  • تسريع النمو من خلال توفير حافز للمستخدمين لدعوة أصدقائهم.
  • تعمل روابط الدعوة عبر الأنظمة الأساسية.
  • يحصل المستخدمون الجدد الذين يفتحون تطبيقك لأول مرة على تجربة التشغيل الأولى التي تخصصها لهم. على سبيل المثال ، يمكنك ربطهم تلقائيًا بالصديق الذي دعاهم.
  • اختياريًا ، يمكنك تأخير منح المكافآت حتى يكمل المستخدمون الجدد بعض المهام التمهيدية ، مثل إكمال برنامج تعليمي.

إليك كيفية البدء!

إعداد Firebase و Dynamic Links SDK

قم بإعداد مشروع Firebase جديد وتثبيت Dynamic Links SDK في تطبيقك. ( iOS ، Android ، C ++ ، Unity ). يسمح تثبيت Dynamic Links SDK لـ Firebase بتمرير البيانات حول الرابط الديناميكي إلى التطبيق ، بما في ذلك بعد تثبيت المستخدم للتطبيق. بدون SDK ، لا توجد طريقة لتوصيل مستخدم ما بعد التثبيت بنقرة التثبيت المسبق.

لإنشاء دعوة ، قم أولاً بإنشاء الرابط الذي يفتحه المستلم لقبول الدعوة. لاحقًا ، ستقوم بتضمين هذا الرابط في نص الدعوة. عندما يقوم مستلم الدعوة بتثبيت تطبيقك عن طريق فتح الرابط ، يمكنه الحصول على تجربة تشغيل مخصصة لأول مرة ، بما في ذلك تلقي مكافأة داخل التطبيق.

رابط الدعوة هذا عبارة عن رابط ديناميكي مع قيمة معلمة link تشير إلى أنه من مستخدم موجود لديك.

هناك العديد من الطرق التي يمكنك من خلالها تنسيق حمولات معلمات link هذه وربطها بتطبيقك. تتمثل إحدى الطرق البسيطة في تحديد معرف حساب المستخدم الخاص بالمرسل في معلمة استعلام كما في المثال التالي:

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

بعد ذلك ، لإنشاء روابط ديناميكية مناسبة للتضمين في دعوة ، يمكنك استخدام Dynamic Link Builder API:

سويفت

ملاحظة: لا يتوفر منتج Firebase هذا على أهداف macOS أو Mac Catalyst أو tvOS أو 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
}

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+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
    // ...
}

إرسال الدعوات

الآن بعد أن أنشأت الرابط ، يمكنك إدراجه في دعوة. يمكن أن تكون الدعوة رسالة بريد إلكتروني أو رسالة نصية قصيرة أو أي وسيلة أخرى ، اعتمادًا على ما هو أكثر ملاءمة لتطبيقك وجمهورك.

على سبيل المثال ، لإرسال دعوة بالبريد الإلكتروني:

سويفت

ملاحظة: لا يتوفر منتج Firebase هذا على أهداف macOS أو Mac Catalyst أو tvOS أو 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)

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

استرجع معلومات الإحالة في تطبيقك

عندما يفتح مستلم الدعوة رابط الإحالة ، سيتم توجيهه إلى App Store أو Play Store لتثبيت تطبيقك إذا لم يكن مثبتًا بالفعل. بعد ذلك ، عندما يفتحون تطبيقك لأول مرة ، يمكنك استرداد معلومات الإحالة التي قمت بتضمينها في الرابط الديناميكي واستخدامها لتطبيق المكافأة.

عادة ، تريد منح مكافآت الإحالة فقط بعد تسجيل مستلم الدعوة ، أو حتى بعد أن يكمل المستخدم الجديد بعض المهام فقط. حتى يتم استيفاء معايير المكافأة ، تحتاج إلى تتبع معلومات المكافأة التي حصلت عليها من الرابط الديناميكي.

طريقة واحدة لتتبع هذه المعلومات هي تسجيل دخول المستخدم بشكل مجهول وتخزين البيانات في سجل Realtime Database الخاص بالحساب المجهول. عندما يقوم المستلم بالتسجيل ويتم تحويل الحساب المجهول إلى حساب دائم ، سيكون للحساب الجديد نفس المعرف الفريد للحساب المجهول ، ونتيجة لذلك ، سيتمكن من الوصول إلى معلومات المكافأة.

على سبيل المثال ، لحفظ UID الخاص بالمحيل بعد أن يفتح المستلم تطبيقك:

سويفت

ملاحظة: لا يتوفر منتج Firebase هذا على أهداف macOS أو Mac Catalyst أو tvOS أو 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.
        }
      }
    }
  }
}

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

بعد ذلك ، عندما يقرر مستلم الدعوة إنشاء حساب ، يمكنك نقل معلومات الإحالة من الحساب المجهول إلى الحساب الجديد لمتلقي الدعوة.

أولاً ، احصل على كائن AuthCredential باستخدام طريقة تسجيل الدخول التي يريد المدعو استخدامها. على سبيل المثال ، لتسجيل الدخول بعنوان بريد إلكتروني وكلمة مرور:

سويفت

ملاحظة: لا يتوفر منتج Firebase هذا على أهداف macOS أو Mac Catalyst أو tvOS أو watchOS.
let credential = EmailAuthProvider.credential(withEmail: email, password: password)

Java

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

Kotlin+KTX

val credential = EmailAuthProvider.getCredential(email, password)

بعد ذلك ، اربط بيانات الاعتماد هذه بالحساب المجهول:

سويفت

ملاحظة: لا يتوفر منتج Firebase هذا على أهداف macOS أو Mac Catalyst أو tvOS أو watchOS.
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+KTX

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

يتمتع الحساب الجديد والدائم بإمكانية الوصول إلى جميع بيانات المكافأة التي أضفتها إلى الحساب المجهول.

امنح المكافآت للمحيل والمتلقي

الآن بعد أن استرجعت بيانات الدعوة وحفظتها من الرابط الديناميكي ، يمكنك منح مكافآت الإحالة للمحيل والمستلم متى تم استيفاء المعايير التي تريد طلبها.

على الرغم من أنه يمكنك الكتابة إلى Realtime Database من تطبيق العميل الخاص بك ، فغالبًا ما تريد السماح فقط بالوصول للقراءة إلى البيانات مثل العملة داخل التطبيق من تطبيقاتك ، وإجراء عمليات الكتابة فقط من الواجهة الخلفية الخاصة بك. يمكن أن تكون هذه الواجهة الخلفية أي نظام قادر على تشغيل Firebase Admin SDK ، ولكن غالبًا ما يكون من الأسهل استخدام وظائف السحابة لأداء هذه المهام.

على سبيل المثال ، لنفترض أن لديك لعبة وترغب في منح مكافأة بعملة داخل اللعبة إلى المستلم بعد تسجيل المستلم ، وإلى المُحيل بعد وصول المستلم إلى المستوى 5.

لمنح مكافأة التسجيل ، انشر وظيفة تراقب إنشاء مفتاح قاعدة بيانات Realtime معين ، وتمنح المكافأة عندما تكون كذلك. فمثلا:

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

بعد ذلك ، عندما يقوم مستخدم جديد بالتسجيل ، قم بتشغيل هذه الوظيفة عن طريق إنشاء مفتاح Realtime Database. على سبيل المثال ، قم بتشغيل الوظيفة في مستمع نجاح linkWithCredential ، والذي قمت بإنشائه في الخطوة السابقة:

سويفت

ملاحظة: لا يتوفر منتج Firebase هذا على أهداف macOS أو Mac Catalyst أو tvOS أو 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())
    }
  }
}

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

لمنح مكافأة للمحيل عندما يصل المستلم إلى المستوى 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;
            });
          }
        });
      }
    });

لقد تلقى كل من المُحيل والمستخدم الجديد مكافآتهما الآن.