Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Conquiste novos usuários recompensando as referências de usuários

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

Uma das maneiras mais eficazes de obter novos usuários é por meio de referências de usuários. Você pode usar Dynamic Links junto com Realtime Database e Cloud Functions para Firebase para encorajar seus usuários a convidar seus amigos, oferecendo recompensas no aplicativo por indicações bem-sucedidas tanto para o referenciador quanto para o destinatário.

Principais benefícios

  • Acelere o crescimento fornecendo um incentivo para que seus usuários convidem seus amigos.
  • Os links de convite funcionam em várias plataformas.
  • Novos usuários que abrem seu aplicativo pela primeira vez obtêm uma experiência de primeira execução que você personaliza para eles. Por exemplo, você pode conectá-los automaticamente ao amigo que os convidou.
  • Opcionalmente, adie a concessão de recompensas até que novos usuários concluam alguma tarefa introdutória, como concluir um tutorial.

Veja como começar!

Configurar o Firebase e o SDK do Dynamic Links

Configure um novo projeto do Firebase e instale o SDK do Dynamic Links em seu aplicativo. ( iOS , Android , C++ , Unity ). A instalação do SDK do Dynamic Links permite que o Firebase transmita dados sobre o Dynamic Link para o aplicativo, inclusive depois que o usuário instala o aplicativo. Sem o SDK, não há como conectar um usuário pós-instalação com um clique pré-instalação.

Para criar um convite, primeiro crie o link que o destinatário abre para aceitar o convite. Posteriormente, você incluirá este link no texto do convite. Quando um destinatário do convite instala seu aplicativo abrindo o link, ele pode obter uma experiência de primeira execução personalizada, incluindo o recebimento de uma recompensa no aplicativo.

Este link de convite é um link dinâmico com um valor de parâmetro de link que indica que é de seu usuário existente.

Há muitas maneiras de formatar esses payloads de parâmetro de link e vinculá-los ao seu aplicativo. Uma maneira simples é especificar o ID da conta de usuário do remetente em um parâmetro de consulta, como no exemplo a seguir:

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

Em seguida, para criar links dinâmicos adequados para inclusão em um convite, você pode usar a API do Dynamic Link Builder:

Rápido

Nota: este produto Firebase não está disponível em destinos macOS, Mac Catalyst, tvOS ou 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();
                // ...
            }
        });

Envie os convites

Agora que você criou o link, pode incluí-lo em um convite. O convite pode ser um e-mail, mensagem SMS ou qualquer outro meio, dependendo do que for mais adequado para seu app e público.

Por exemplo, para enviar um convite por e-mail:

Rápido

Nota: este produto Firebase não está disponível em destinos macOS, Mac Catalyst, tvOS ou 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);
}

Recupere informações de referência em seu aplicativo

Quando o destinatário do convite abrir o link de referência, ele será direcionado para a App Store ou Play Store para instalar seu aplicativo, caso ainda não esteja instalado. Então, quando eles abrirem seu aplicativo pela primeira vez, você poderá recuperar as informações de referência incluídas no link dinâmico e usá-las para aplicar a recompensa.

Normalmente, você deseja conceder recompensas de indicação somente após o destinatário do convite se inscrever ou mesmo após o novo usuário concluir alguma tarefa. Até que os critérios de recompensa sejam atendidos, você precisa acompanhar as informações de recompensa obtidas no link dinâmico.

Uma maneira de acompanhar essas informações é fazer login do usuário anonimamente e armazenar os dados no registro do Realtime Database da conta anônima. Quando o destinatário se inscrever e a conta anônima for convertida em uma conta permanente, a nova conta terá o mesmo UID da conta anônima e, como resultado, terá acesso às informações da recompensa.

Por exemplo, para salvar o UID do referenciador depois que o destinatário abrir seu aplicativo:

Rápido

Nota: este produto Firebase não está disponível em destinos macOS, Mac Catalyst, tvOS ou 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);
                }
            });
}

Então, quando o destinatário do convite decidir criar uma conta, você poderá transferir as informações de referência da conta anônima para a nova conta do destinatário do convite.

Primeiro, obtenha um objeto AuthCredential usando o método de login que o convidado deseja usar. Por exemplo, para entrar com um endereço de e-mail e senha:

Rápido

Nota: este produto Firebase não está disponível em destinos macOS, Mac Catalyst, tvOS ou watchOS.
let credential = EmailAuthProvider.credential(withEmail: email, password: password)

Kotlin+KTX

val credential = EmailAuthProvider.getCredential(email, password)

Java

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

Em seguida, vincule esta credencial à conta anônima:

Rápido

Nota: este produto Firebase não está disponível em destinos macOS, Mac Catalyst, tvOS ou 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.
            }
        });

A nova conta permanente tem acesso a todos os dados de recompensa que você adicionou à conta anônima.

Conceda recompensas ao referenciador e ao destinatário

Agora que você recuperou e salvou os dados do convite do Dynamic Link, você pode conceder as recompensas de referência ao referenciador e ao destinatário sempre que os critérios que você deseja exigir forem atendidos.

Embora você possa gravar no Realtime Database a partir de seu aplicativo cliente, muitas vezes você deseja permitir apenas o acesso de leitura a dados como a moeda do aplicativo de seus aplicativos e executar operações de gravação apenas de seu back-end. Esse back-end pode ser qualquer sistema capaz de executar o Firebase Admin SDK, mas geralmente é mais fácil usar o Cloud Functions para executar essas tarefas.

Por exemplo, suponha que você tenha um jogo e queira conceder uma recompensa em moeda do jogo ao destinatário depois que ele se inscrever e ao referenciador depois que o destinatário atingir o nível 5.

Para conceder a recompensa pela inscrição, implante uma função que observe a criação de uma chave específica do Realtime Database e conceda a recompensa quando isso acontecer. Por exemplo:

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

Em seguida, quando um novo usuário se inscrever, acione essa função criando a chave do Realtime Database. Por exemplo, acione a função no ouvinte de sucesso de linkWithCredential , que você criou na etapa anterior:

Rápido

Nota: este produto Firebase não está disponível em destinos macOS, Mac Catalyst, tvOS ou 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);
            }
        });

Para conceder uma recompensa ao referenciador quando o destinatário atingir o nível 5, implemente uma função que observe as alterações no campo de level em seus registros de usuário. Se um usuário passou do nível 4 para o nível 5 e o usuário tem um referenciador registrado, conceda a 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;
            });
          }
        });
      }
    });

Tanto o referenciador quanto seu novo usuário já receberam suas recompensas.