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 sugerir a los usuarios que inviten a sus amigos y ofrecer recompensas en la app al usuario existente y al nuevo cada vez que alguien acepta 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 tu app por primera vez tienen una experiencia inicial personalizada para ellos. 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++, 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.

Para crear una invitación, primero crea el vínculo que el destinatario abrirá para aceptarla. Luego incluirás 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, puede obtener una experiencia inicial personalizada, que puede incluir 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 en el cual se indica que proviene de tu usuario existente.

Hay muchas maneras en las que puedes dar formato a estas cargas útiles del parámetro link y vincularlas a tu app. Una forma sencilla es especificar el ID de cuenta de usuario del remitente 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: "abc123.app.goo.gl")

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("abc123.app.goo.gl")
        .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 electrónico, SMS o de cualquier otro medio, según lo que sea adecuado para tu app y tu 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 tu app por primera vez, puede recuperar la información de la referencia que incluiste en el Dynamic Link y usarla para obtener la recompensa.

Por lo general, 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 de la recompensa 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 remitente después de que el destinatario abra tu 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, puedes 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 remitente y al destinatario

Ahora que ya recuperaste y guardaste los datos de la invitación del Dynamic Link, podrás recompensar al remitente y al destinatario por la referencia cuando se cumplan 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 remitente 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 crea 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 un usuario nuevo se registre, 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 remitente 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 nivel 5 y tiene una referencia registrada, 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 remitente como tu usuario nuevo habrán recibido sus recompensas.

Enviar comentarios sobre…

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