Google is committed to advancing racial equity for Black communities. See how.
ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

مكافأة الإحالات

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

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

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

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

إعداد Firebase و Dynamic Links SDK

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

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

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

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

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
}
 

جافا

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

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

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

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

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)
 

جافا

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

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

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

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

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

على سبيل المثال ، لحفظ 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
}
 

جافا

@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 باستخدام طريقة تسجيل الدخول التي يريد المدعو استخدامها. على سبيل المثال ، لتسجيل الدخول باستخدام عنوان بريد إلكتروني وكلمة مرور:

iOS (Swift)

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

جافا

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

Kotlin + KTX

val 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.
  }
}
 

جافا

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 من تطبيق العميل الخاص بك ، إلا أنك غالبًا ما ترغب في السماح بالوصول للقراءة فقط إلى البيانات مثل العملة داخل التطبيق من تطبيقاتك ، وإجراء عمليات الكتابة فقط من الواجهة الخلفية. يمكن أن تكون هذه الواجهة الخلفية أي نظام قادر على تشغيل حزمة 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. على سبيل المثال ، قم بتشغيل الوظيفة في مستمع نجاح 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())
    }
  }
}
 

جافا

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

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