Atraia novos usuários para o app, permitindo que eles compartilhem o conteúdo do app

Uma das maneiras mais eficazes para que novos usuários instalem apps é permitir que compartilhem o conteúdo do app com os amigos. Com o Dynamic Links, você cria uma ótima experiência de compartilhamento entre os usuários. Usuários que recebem recomendações de conteúdo dos amigos podem clicar em um link que os leva diretamente ao conteúdo compartilhado no app, mesmo que tenham de ir antes à App Store ou à Google Play Store para instalar o app.

Ao combinar a aderência das indicações de usuários e a persistência do Dynamic Links, é possível criar recursos de compartilhamento e encaminhamento de usuário para usuário que atraem pessoas novas diretamente para o conteúdo do seu app ou veiculam promoções que beneficiam tanto quem fez a indicação quanto quem a recebeu.

Principais benefícios

  • Os novos usuários que abrem o app pela primeira vez têm uma primeira experiência personalizada que é contextualizada com base no que a pessoa que fez a indicação queria compartilhar. Por exemplo, é possível exibir o conteúdo compartilhado com eles ou conectá-los automaticamente ao amigo que os convidou.
  • Facilita o compartilhamento de conteúdo dos usuários com os amigos entre plataformas diferentes, independentemente de o app ser instalado ou não pelos amigos.

Veja como começar.

Configure um novo projeto do Firebase e instale o SDK do Dynamic Links no seu app.

Com a instalação do SDK do Dynamic Links, o Firebase pode transmitir dados do link dinâmico para o app, inclusive depois que o usuário instala o app.

Agora é hora de configurar os links que os usuários podem enviar aos amigos. Não se preocupe se as pessoas que você indicou ainda não tiverem instalado o app. O Dynamic Links cuida disso por você.

Crie um link dinâmico para cada elemento de conteúdo que você quer compartilhar.

Ao criar o Dynamic Link, você vai precisar fornecer um URL HTTP ou HTTPS como o parâmetro link. Ele será usado para identificar o conteúdo que você está compartilhando. Se você tiver um site com conteúdo equivalente, use os URLs dele. Isso garante que esses links sejam renderizados corretamente em uma plataforma que não oferece suporte ao Dynamic Links, como um navegador para computador. Exemplo:

https://example.page.link/?link=https://www.example.com/content?item%3D1234&apn=com.example.android&ibi=com.example.ios&isi=12345

Também é possível adicionar mais informações ao payload de dados adicionando parâmetros codificados em URL. Por exemplo, para indicar que o link é destinado a um usuário específico, como em um convite de jogo.

https://example.page.link/?link=https://www.example.com/invitation?gameid%3D1234%26referrer%3D555&apn=com.example.android&ibi=com.example.ios&isi=12345

Antes de compartilhar esses links, use a API Firebase Dynamic Links URL shortener para facilitar o uso deles. Um link dinâmico curto tem a seguinte aparência:

https://example.page.link/WXYZ

Independentemente do link usado, quando os usuários abrirem o link dinâmico no dispositivo, o app especificado pelos parâmetros apn (no Android) ou ibi e isi (no iOS) vai direcionar os usuários à Play Store ou App Store para instalá-lo, caso isso ainda não tenha sido feito. Em seguida, quando o app for instalado e aberto, o URL especificado no parâmetro "link" será transmitido para o aplicativo.

Primeiro, veja este exemplo simples de um app de chat dividido em salas, como o Hangouts, que gera links para convidar pessoas para salas de chat.

iOS

captura de tela do app de chat captura de tela do app de chat com página de compartilhamento

Android

captura de tela do app de chat captura de tela do app de chat com página de compartilhamento

Swift

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
func generateContentLink() -> URL {
  let baseURL = URL(string: "https://your-custom-name.page.link")!
  let domain = "https://your-app.page.link"
  let linkBuilder = DynamicLinkComponents(link: baseURL, domainURIPrefix: domain)
  linkBuilder?.iOSParameters = DynamicLinkIOSParameters(bundleID: "com.your.bundleID")
  linkBuilder?.androidParameters =
      DynamicLinkAndroidParameters(packageName: "com.your.packageName")

  // Fall back to the base url if we can't generate a dynamic link.
  return linkBuilder?.link ?? baseURL
}

Objective-C

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
- (NSURL *)generateContentLink {
  NSURL *baseURL = [NSURL URLWithString:@"https://your-custom-name.page.link"];
  NSString *domain = @"https://your-app.page.link";
  FIRDynamicLinkComponents *builder = [[FIRDynamicLinkComponents alloc] initWithLink:baseURL domainURIPrefix:domain];
  builder.iOSParameters = [FIRDynamicLinkIOSParameters parametersWithBundleID:@"com.your.bundleID"];
  builder.androidParameters = [FIRDynamicLinkAndroidParameters parametersWithPackageName:@"com.your.packageName"];

  // Fall back to the base url if we can't generate a dynamic link.
  return builder.link ?: baseURL;
}

Kotlin+KTX

fun generateContentLink(): Uri {
    val baseUrl = Uri.parse("https://your-custom-name.page.link")
    val domain = "https://your-app.page.link"

    val link = FirebaseDynamicLinks.getInstance()
            .createDynamicLink()
            .setLink(baseUrl)
            .setDomainUriPrefix(domain)
            .setIosParameters(DynamicLink.IosParameters.Builder("com.your.bundleid").build())
            .setAndroidParameters(DynamicLink.AndroidParameters.Builder("com.your.packageName").build())
            .buildDynamicLink()

    return link.uri
}

Java

public static Uri generateContentLink() {
    Uri baseUrl = Uri.parse("https://your-custom-name.page.link");
    String domain = "https://your-app.page.link";

    DynamicLink link = FirebaseDynamicLinks.getInstance()
            .createDynamicLink()
            .setLink(baseUrl)
            .setDomainUriPrefix(domain)
            .setIosParameters(new DynamicLink.IosParameters.Builder("com.your.bundleid").build())
            .setAndroidParameters(new DynamicLink.AndroidParameters.Builder("com.your.packageName").build())
            .buildDynamicLink();

    return link.getUri();
}

Depois de gerar um link dinâmico, é possível adicionar um botão de compartilhamento à IU que iniciará o fluxo de compartilhamento de plataforma padrão:

Swift

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
lazy private var shareController: UIActivityViewController = {
  let activities: [Any] = [
    "Learn how to share content via Firebase",
    URL(string: "https://firebase.google.com")!
  ]
  let controller = UIActivityViewController(activityItems: activities,
                                            applicationActivities: nil)
  return controller
}()

@IBAction func shareButtonPressed(_ sender: Any) {
  let inviteController = UIStoryboard(name: "Main", bundle: nil)
    .instantiateViewController(withIdentifier: "InviteViewController")
  self.navigationController?.pushViewController(inviteController, animated: true)
}

Objective-C

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
- (UIActivityViewController *)shareController {
  if (_shareController == nil) {
    NSArray *activities = @[
      @"Learn how to share content via Firebase",
      [NSURL URLWithString:@"https://firebase.google.com"]
    ];
    UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:activities applicationActivities:nil];
    _shareController = controller;
  }
  return _shareController;
}

- (IBAction)shareLinkButtonPressed:(UIView *)sender {
  if (![sender isKindOfClass:[UIView class]]) {
    return;
  }

  self.shareController.popoverPresentationController.sourceView = sender;
  [self presentViewController:self.shareController animated:YES completion:nil];
}

Kotlin+KTX

private fun onShareClicked() {
    val link = DynamicLinksUtil.generateContentLink()

    val intent = Intent(Intent.ACTION_SEND)
    intent.type = "text/plain"
    intent.putExtra(Intent.EXTRA_TEXT, link.toString())

    startActivity(Intent.createChooser(intent, "Share Link"))
}

Java

private void onShareClicked() {
    Uri link = DynamicLinksUtil.generateContentLink();

    Intent intent = new Intent(Intent.ACTION_SEND);
    intent.setType("text/plain");
    intent.putExtra(Intent.EXTRA_TEXT, link.toString());

    startActivity(Intent.createChooser(intent, "Share Link"));
}

Neste exemplo, a IU de compartilhamento padrão apresenta automaticamente uma lista de apps para compartilhar o link. Isso pode ser configurado no seu próprio aplicativo com apenas algumas linhas de código.

Em vez de o usuário selecionar contatos e redigir a mensagem no app, essas ações são delegadas ao aplicativo escolhido na caixa de diálogo de compartilhamento. Além disso, delegar o compartilhamento a outros apps significa que você não precisa solicitar permissões de acesso aos contatos dos usuários, e eles poderão selecionar os contatos que quiserem em uma lista expandida no app escolhido. Para facilitar o compartilhamento nas redes sociais, é possível adicionar metadados de visualização de mídias sociais ao link dinâmico. Eles vão aparecer nos principais canais sociais.

No entanto, às vezes, apenas enviar um link sem texto não é suficiente para uma indicação atrativa. Adicionar uma mensagem curta e, se possível, uma apresentação mais completa junto ao link ajuda os usuários a entender a proposta de valor da indicação quando a recebem:

iOS

captura de tela de indicação premiada captura de tela da indicação premiada com página de compartilhamento

Android

captura de tela de indicação premiada captura de tela da indicação premiada com página de compartilhamento

Embora isso seja mais complexo do que o último exemplo, a abordagem será semelhante. Nesta tela, há um gráfico grande com a proposta de valor do convite e botões para compartilhar nos principais canais sociais. Há um pouco de redundância nesse fluxo da IU: alguns canais de compartilhamento são apresentados individualmente para permitir uma personalização maior da mensagem específica do canal, como adicionar uma linha de assunto aos convites por e-mail. Neste menu de convite, é possível realizar as seguintes ações:

  • Apresentar botões de compartilhamento por e-mail, mensagem de texto ou link, além de personalizar as mensagens de maneira adequada. O e-mail tem um assunto e pode incluir um corpo mais longo com quebras de linha, imagens e espaços em branco. A mensagem de texto deve ser mais curta e pode ter quebras de linha, mas com pouco espaço em branco e sem imagens. O compartilhamento por link apenas copia essa informação e nada mais.
  • Usar a IU de compartilhamento do sistema para todo o restante, incluindo uma breve mensagem de convite para acompanhar o link.
  • Incluir um link direto usando o esquema de URL ou link universal para outro app que tenha uma lógica especial para lidar com os convites do seu app. Isso não funcionará sem uma parceria entre sua organização e o outro app, e provavelmente não é uma opção para organizações menores. Dito isso, alguns apps podem documentar publicamente o comportamento de vinculação universal/direta deles. Vamos implementar uma versão fictícia disso na nossa amostra.

Primeiro, defina um tipo de conteúdo de convite, que agrega apenas as informações em um convite e não contém funcionalidade. Assim, é possível começar com os tipos de dados e pensar no seu código em termos de como eles são reunidos.

Swift

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
/// The content within an invite, with optional fields to accommodate all presenters.
/// This type could be modified to also include an image, for sending invites over email.
struct InviteContent {

  /// The subject of the message. Not used for invites without subjects, like text message invites.
  var subject: String?

  /// The body of the message. Indispensable content should go here.
  var body: String?

  /// The URL containing the invite. In link-copy cases, only this field will be used.
  var link: URL

}

Objective-C

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
/// The content within an invite, with optional fields to accommodate all presenters.
/// This type could be modified to also include an image, for sending invites over email.
@interface InviteContent : NSObject <NSCopying>

/// The subject of the message. Not used for invites without subjects, like text message invites.
@property (nonatomic, readonly, nullable) NSString *subject;

/// The body of the message. Indispensable content should go here.
@property (nonatomic, readonly, nullable) NSString *body;

/// The URL containing the invite. In link-copy cases, only this field will be used.
@property (nonatomic, readonly) NSURL *link;

- (instancetype)initWithSubject:(nullable NSString *)subject
                           body:(nullable NSString *)body
                           link:(NSURL *)link NS_DESIGNATED_INITIALIZER;

- (instancetype)init NS_UNAVAILABLE;

@end

Kotlin+KTX

/**
 * The content of an invitation, with optional fields to accommodate all presenters.
 * This type could be modified to also include an image, for sending invites over email.
 */
data class InviteContent(
    /** The subject of the message. Not used for invites without subjects, like SMS.  */
    val subject: String?,
    /** The body of the message. Indispensable content should go here.  */
    val body: String?,
    /** The URL containing the link to invite. In link-copy cases, only this field will be used.  */
    val link: Uri
)

Java

/**
 * The content of an invitation, with optional fields to accommodate all presenters.
 * This type could be modified to also include an image, for sending invites over email.
 */
public class InviteContent {

    /**
     * The subject of the message. Not used for invites without subjects, like SMS.
     **/
    @Nullable
    public final String subject;

    /**
     * The body of the message. Indispensable content should go here.
     **/
    @Nullable
    public final String body;

    /**
     * The URL containing the link to invite. In link-copy cases, only this field will be used.
     **/
    @NonNull
    public final Uri link;

    public InviteContent(@Nullable String subject, @Nullable String body, @NonNull Uri link) {
        // ...
    }

}

A única informação necessária aqui é o URL. Sem ele, você não vai conseguir convidar os usuários para o app. Os outros dados são estruturados claramente para o uso em e-mails, o que os torna um pouco estranhos em outros casos. Quando um convite é enviado por mensagem de texto, o anúncio que acompanha o link pode parecer um assunto de e-mail. Ainda assim, quando esse link é compartilhado nas mídias sociais, ele pode parecer um corpo de e-mail. Faça testes para encontrar a abordagem mais adequada ao seu app e, se não tiver certeza, use um serviço como a Configuração remota para alterar os valores de texto após o lançamento do app.

Swift

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
/// A type responsible for presenting an invite given using a specific method
/// given the content of the invite.
protocol InvitePresenter {

  /// The name of the presenter. User-visible.
  var name: String { get }

  /// An icon representing the invite method. User-visible.
  var icon: UIImage? { get }

  /// Whether or not the presenter's method is available. iOS devices that aren't phones
  /// may not be able to send texts, for example.
  var isAvailable: Bool { get }

  /// The content of the invite. Some of the content type's fields may be unused.
  var content: InviteContent { get }

  /// Designated initializer.
  init(content: InviteContent, presentingController: UIViewController)

  /// This method should cause the presenter to present the invite and then handle any actions
  /// required to complete the invite flow.
  func sendInvite()

}

Objective-C

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
/// A type responsible for presenting an invite given using a specific method
/// given the content of the invite.
@protocol InvitePresenter <NSObject>

/// The name of the presenter. User-visible.
@property (nonatomic, readonly) NSString *name;

/// An icon representing the invite method. User-visible.
@property (nonatomic, readonly, nullable) UIImage *icon;

/// Whether or not the presenter's method is available. iOS devices that aren't phones
/// may not be able to send texts, for example.
@property (nonatomic, readonly) BOOL isAvailable;

/// The content of the invite. Some of the content type's fields may be unused.
@property (nonatomic, readonly) InviteContent *content;

/// Designated initializer.
- (instancetype)initWithContent:(InviteContent *)content presentingViewController:(UIViewController *)controller;

/// This method should cause the presenter to present the invite and then handle any actions
/// required to complete the invite flow.
- (void)sendInvite;

@end

Kotlin+KTX

/**
 * Presents the invite using a specific method, such as email or social.
 */
open class InvitePresenter(
    /** The user-visible name of the invite method, like 'Email' or 'SMS'  */
    val name: String,
    /** An icon representing the invite method.  */
    @param:DrawableRes @field:DrawableRes
    val icon: Int,
    /** Whether or not the method is available on this device. For example, SMS is phone only.  */
    val isAvailable: Boolean,
    /** The Content of the invitation  */
    val content: InviteContent
) {
    /**
     * Send the invitation using the specified method.
     */
    open fun sendInvite(context: Context) {
        // ...
    }
}

Java

/**
 * Presents the invite using a specific method, such as email or social.
 */
public class InvitePresenter {

    /**
     * The user-visible name of the invite method, like 'Email' or 'SMS'
     **/
    public final String name;

    /**
     * An icon representing the invite method.
     **/
    @DrawableRes
    public final int icon;

    /**
     * Whether or not the method is available on this device. For example, SMS is phone only.
     **/
    public final boolean isAvailable;

    /**
     * The Content of the invitation
     **/
    public final InviteContent content;

    public InvitePresenter(String name, @DrawableRes int icon, boolean isAvailable, InviteContent content) {
        // ...
    }

    /**
     * Send the invitation using the specified method.
     */
    public void sendInvite(Context context) {
        // ...
    }

}

Agora só falta incluir esses dados em um componente de IU de sua escolha. Para saber mais sobre a implementação completa desse fluxo de convite, consulte as amostras no GitHub para iOS e Android.

Esses são os métodos para permitir que seus usuários enviem convites aos amigos deles, que é a solução de convite mais leve. Muitos apps conhecidos também enviam convites nos e-mails usando o próprio back-end, o que exige a integração de um serviço de envio de e-mails, mas oferece vários benefícios que não estão disponíveis de outra forma, apenas com algumas pequenas desvantagens.

Vantagens:

  • Permite o envio de e-mails com marcação complexa que não podem ser modificados pelo usuário antes do envio.
  • Permite um rastreamento e uma análise mais granulares (ou seja, sucessos e falhas de envio no back-end).

Desvantagens:

  • Os e-mails são mais propensos a serem sinalizados como spam.
  • Requer uma integração com um serviço de envio de e-mail.
  • Requer permissões de acesso aos contatos no app.

Geralmente, o envio de convites usando seu próprio serviço de envio de e-mail oferece uma experiência de convite mais consistente e potencialmente mais complexa, mas menos versátil.

Abrir o conteúdo vinculado no app

Por fim, você precisa receber o link transmitido ao app para exibir o conteúdo vinculado ao destinatário. É fácil fazer isso usando o SDK do Dynamic Links:

iOS

No iOS, você recebe o link dinâmico ao implementar o método application:continueUserActivity:restorationHandler:. No gerenciador de restauração, acesse o link dinâmico chamando handleUniversalLink:completion:. Se um link dinâmico tiver sido transmitido ao seu app, você poderá encontrá-lo na propriedade url do FIRDynamicLink. Exemplo:

Objective-C

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
[[FIRDynamicLinks dynamicLinks]
    handleUniversalLink:userActivity.webpageURL
             completion:^(FIRDynamicLink * _Nullable dynamicLink,
                          NSError * _Nullable error) {
      NSString *link = dynamicLink.url;
      BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
      // ...
    }];

Swift

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
FIRDynamicLinks.dynamicLinks()?.handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
    let link = dynamicLink.url
    let strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong
    // ...
}

Além disso, é preciso chamar dynamicLinkFromCustomSchemeURL: no método application:openURL:options: para receber os links dinâmicos transmitidos ao seu app como URLs de esquema personalizado. Por exemplo:

Objective-C

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink) {
  NSString *link = dynamicLink.url;
  BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
  // ...
  return YES;
}

Swift

Observação: este produto do Firebase não está disponível para destinos macOS, Mac Catalyst, tvOS ou watchOS.
let dynamicLink = FIRDynamicLinks.dynamicLinks()?.dynamicLinkFromCustomSchemeURL(url)
if let dynamicLink = dynamicLink {
  let link = dynamicLink.url
  let strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong
  // ...
  return true
}

Agora que você tem o valor do parâmetro link, pode mostrar o conteúdo vinculado ao destinatário ou processar os dados especificados pelo parâmetro de outra maneira. Uma biblioteca de roteamento de URL, como JLRoutes (em inglês), pode ajudar nessa tarefa.

Se você estiver recebendo um link que é direcionado a um destinatário específico, verifique se a confiança de correspondência do Dynamic Link é strong antes de executar qualquer lógica específica ao usuário.

Android

No Android, use o método getDynamicLink() para receber dados do link dinâmico:

Kotlin+KTX

Firebase.dynamicLinks
        .getDynamicLink(intent)
        .addOnCompleteListener { task ->
            if (!task.isSuccessful) {
                // Handle error
                // ...
            }

            val invite = FirebaseAppInvite.getInvitation(task.result)
            if (invite != null) {
                // Handle invite
                // ...
            }
        }

Java

FirebaseDynamicLinks.getInstance()
        .getDynamicLink(getIntent())
        .addOnCompleteListener(new OnCompleteListener<PendingDynamicLinkData>() {
            @Override
            public void onComplete(@NonNull Task<PendingDynamicLinkData> task) {
                if (!task.isSuccessful()) {
                    // Handle error
                    // ...
                }

                FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(task.getResult());
                if (invite != null) {
                    // Handle invite
                    // ...
                }
            }
        });

Agora que você tem o valor do parâmetro link, pode mostrar o conteúdo vinculado ao destinatário ou processar os dados especificados pelo parâmetro de outra maneira. Uma biblioteca de roteamento de URL pode ajudar nessa tarefa.