Recompensa las referencias

Una de las maneras más eficaces de obtener usuarios nuevos es a través de las referencias de usuarios. Si combinas Dynamic Links con Realtime Database y Cloud Functions para Firebase, puedes sugerirles a los usuarios que inviten a sus amigos y ofrecer recompensas en la app para el referente y el destinatario cada vez que alguien acepte una invitación.

Ventajas clave

  • Acelera el crecimiento mediante un incentivo para que tus usuarios inviten a sus amigos.
  • Los vínculos de invitación funcionan en todas las plataformas.
  • Los usuarios nuevos que abren la app por primera vez obtienen una experiencia inicial personalizada. Por ejemplo, puedes conectarlos automáticamente con el amigo que los invitó.
  • De forma opcional, demora la entrega de las recompensas hasta que los usuarios nuevos realicen alguna tarea introductoria, como completar un instructivo.

Aquí te explicaremos cómo comenzar a usar los Dynamic Links.

Configura Firebase y el SDK de Dynamic Links

Configura un nuevo proyecto de Firebase y después instala el SDK de Dynamic Links en la aplicación (iOS, Android, C++ y Unity). Con el SDK de Dynamic Links instalado, Firebase podrá pasar datos acerca del Dynamic Link a la app, incluso si el usuario tiene que instalarla como paso intermedio. Si no tienes el SDK, no hay manera de mostrarle el contenido del vínculo al usuario si tiene que instalar la aplicación como paso intermedio.

A fin de crear una invitación, primero crea el vínculo que abrirá el destinatario para aceptarla. Luego, incluye este vínculo en el texto de la invitación. Cuando el destinatario de una invitación usa el vínculo para instalar tu app, obtiene una experiencia inicial personalizada, que incluye la recepción de una recompensa en la app.

Este vínculo de invitación es un Dynamic Link con un valor de parámetro link que indica que proviene del usuario existente.

Puedes dar formato a estas cargas útiles del parámetro link y vincularlas a la app de muchas maneras. Una forma sencilla es especificar el ID de cuenta de usuario del referente en un parámetro de consulta, como en el ejemplo siguiente:

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

Después, para crear Dynamic Links adecuados para incluirlos en una invitación, puedes usar la API de Dynamic Link Builder:

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

Envía las invitaciones

Ahora que ya creaste el vínculo, puedes incluirlo en una invitación. La invitación puede ser un mensaje de correo, SMS o cualquier otro medio, según lo que sea adecuado para la app y el público.

Por ejemplo, para enviar una invitación por correo electrónico:

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

Recupera la información de referencia en tu app

Cuando el destinatario de la invitación abra el vínculo de referencia, se lo dirigirá a la App Store o a Play Store para instalar la app si aún no está instalada. Luego, cuando abra la app por primera vez, podrás recuperar la información de la referencia que incluiste en el Dynamic Link y usarla para entregar la recompensa.

En términos generales, lo ideal es proporcionar la recompensa de referencia solo después de que el destinatario de la invitación se registre o incluso después de que el usuario nuevo complete alguna tarea. Hasta que se cumplan los criterios para la recompensa, debes hacer un seguimiento de la información respectiva que obtuviste con el Dynamic Link.

Una forma de hacer un seguimiento de esta información es acceder con un usuario anónimo y guardar los datos en el registro de Realtime Database de la cuenta anónima. Cuando el destinatario se registra y la cuenta anónima se convierte en una cuenta permanente, esta cuenta nueva tendrá el mismo UID que la cuenta anónima y, por lo tanto, tendrá acceso a la información de la recompensa.

Por ejemplo, para guardar el UID del referente una vez que el destinatario haya abierto la app:

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

    // ...

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

Después, cuando el destinatario de la invitación decida crear una cuenta, podrás transferir la información de referencia de la cuenta anónima a la cuenta nueva del destinatario de la invitación.

En primer lugar, obtén un objeto AuthCredential mediante el método de acceso que el invitado desea usar. Por ejemplo, para acceder con una dirección de correo electrónico y una contraseña:

iOS (Swift)

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

Android

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

Luego, vincula esta credencial a la cuenta anónima:

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

La cuenta nueva y permanente tiene acceso a todos los datos de recompensas que agregaste a la cuenta anónima.

Ofrece recompensas al referente y al destinatario

Ahora que recuperaste y guardaste los datos de la invitación del Dynamic Link, puedes recompensar al referente y al destinatario por la referencia si se cumplen los criterios que elegiste.

Si bien es posible escribir en Realtime Database desde la app cliente, a menudo es conveniente permitir el acceso de solo lectura a datos como la moneda virtual de tu app y realizar operaciones de escritura solo desde el backend. Este backend podría ser cualquier sistema capaz de ejecutar el SDK de administrador de Firebase, pero a menudo es más fácil usar Cloud Functions para realizar estas tareas.

Por ejemplo, imagina que tienes un juego y deseas ofrecer una recompensa en la moneda virtual del juego al destinatario después de que se registre y al referente después de que el destinatario alcance el nivel 5.

Para proporcionar la recompensa por registrarse, implementa una función que revise cuándo se cree una clave específica de Realtime Database y proporcione la recompensa cuando eso suceda. Por ejemplo:

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

Luego, cuando se registre un usuario nuevo, activa esta función mediante la creación de la clave en Realtime Database. Por ejemplo, activa la función en el agente de escucha de ejecución correcta de linkWithCredential, que creaste en el paso anterior:

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

Para proporcionarle una recompensa al referente cuando el destinatario alcance el nivel 5, implementa una función que observe los cambios en el campo level de tus registros de usuario. Si un usuario pasa del nivel 4 al 5 y tiene un referente registrado, proporciona la recompensa:

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

Con esto, tanto el referente como tu usuario nuevo habrán recibido sus recompensas.

Enviar comentarios sobre…

¿Necesitas ayuda? Visita nuestra página de asistencia.