Ir a la consola

Invita usuarios a tu app

Una de las maneras más eficaces para lograr que los nuevos usuarios instalen tu app es permitirles que compartan contenido de la app con sus amigos. Con Dynamic Links, puedes crear una gran experiencia para tus usuarios cuando comparten contenido con otras personas: los usuarios que reciben recomendaciones de contenido de sus amigos pueden hacer clic en un vínculo para acceder directamente al contenido compartido de tu app, incluso si antes tienen que ir a la App Store o a Google Play Store para instalarla.

Si combinas la adherencia de las referencias de usuario y la persistencia de los Dynamic Links, puedes crear funciones de referencias y de uso compartido entre usuarios que incorporen a nuevos usuarios. Para ello, puedes atraerlos directamente al contenido o publicar promociones en las que el referente y el referido se beneficien mutuamente.

Beneficios clave

  • Los usuarios nuevos que abren tu app por primera vez obtienen una experiencia inicial personalizada que se contextualiza a partir de lo que sus amigos les querían compartir. Por ejemplo, puedes mostrar el contenido que se compartió con ellos o conectarlos automáticamente con el amigo que les envió la invitación.
  • Permite a los usuarios compartir contenido fácilmente con sus amigos en todas las plataformas, sin importar si ellos tienen tu app instalada.

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

Configura Firebase y el SDK de Dynamic Links

Configura un proyecto nuevo de Firebase y después instala el SDK de Dynamic Links en la app.

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.

Crea Dynamic Links

Ahora es momento de configurar los vínculos que los usuarios pueden enviarles a sus amigos. No te preocupes si los usuarios todavía no instalaron la aplicación.

Por cada elemento de contenido que deseas que se pueda compartir, crea un Dynamic Link.

Cuando crees el Dynamic Link, deberás proporcionar una URL HTTP o HTTPS como el parámetro link que se utilizará para identificar el contenido que se comparte. Si tienes un sitio web con contenido equivalente, debes utilizar las URL de tu sitio web. Así, se garantiza que estos vínculos se vean correctamente en una plataforma que no admite Dynamic Links, como un navegador de escritorio. Por ejemplo:

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

También puedes agregar información adicional a la carga útil de datos si incorporas parámetros con codificación URL, por ejemplo, para indicar que el vínculo está destinado a un usuario particular, como una invitación a un juego.

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 compartir estos vínculos, podría ser conveniente que uses la API de abreviación de URL de Firebase Dynamic Links a fin de generar URL más fáciles de leer para el usuario. Un Dynamic Link abreviado tiene el siguiente aspecto:

https://example.page.link/WXYZ

Cualquiera que sea el vínculo que uses, cuando los usuarios abren el Dynamic Link en sus dispositivos, la app especificada por el parámetro apn (en Android) o los ibiisi (en iOS) los llevará a la Play Store o App Store para instalarla si todavía no la tienen. Después, cuando se instala y abre la app, la URL especificada en el parámetro “link” se pasa a la app.

Agrega botones “Compartir” que envían Dynamic Links

Primero, observa este ejemplo simple de una app de chat basada en sala como Hangouts, que genera vínculos para invitar a personas a las salas de chat.

iOS

captura de pantalla de app de chat captura de pantalla de app de chat con hoja compartida

Android

captura de pantalla de app de chat captura de pantalla de app de chat con hoja compartida

Swift

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

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

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

Kotlin

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
}

Una vez que tengas un vínculo dinámico, puedes agregar un botón para compartir a la IU, que iniciará el flujo estándar de uso compartido de la plataforma, como se muestra a continuación:

Swift

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

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

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

Kotlin

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

En este ejemplo, la IU predeterminada para compartir presenta automáticamente una lista de apps con las que se puede compartir el vínculo, por lo que puedes configurar tu app a fin de que aparezca en ella con solo pocas líneas de código.

En lugar de que los usuarios seleccionen los contactos y redacten el mensaje en tu app, se delegan estas acciones a la app que ellos eligen en el diálogo. Además, delegar el uso compartido significa que no deberás pedirles permisos de contactos y les permitirás seleccionar de una lista ampliada en la app elegida. Para facilitar el uso compartido en redes sociales, puedes agregar metadatos de vista previa al vínculo dinámico que se mostrará junto al de los canales principales.

Sin embargo, a veces solo el envío de un vínculo vacío sin texto no es suficiente para una referencia convincente. Si se acompaña un vínculo con un mensaje corto y, en lo posible, una presentación más completa, los usuarios podrán comprender la propuesta de valor de la referencia cuando la reciban:

iOS

captura de pantalla de referencia recompensada captura de pantalla de referencia recompensada con hoja compartida

Android

captura de pantalla de referencia recompensada captura de pantalla de referencia recompensada con hoja compartida

Aunque este es más complejo que el último ejemplo, el enfoque es más o menos el mismo. En la pantalla, hay un gráfico grande con la propuesta de valor de la invitación y los botones para compartir en los canales sociales principales. Hay cierta redundancia en este flujo de la IU, es decir, algunos canales compartidos se presentan individualmente para permitir más personalización en mensajes específicos de canales, como agregar una línea de asunto a las invitaciones de correo electrónico. En este menú de invitación, realizamos lo siguiente:

  • Presentamos los botones para compartir el correo electrónico, el mensaje de texto y el de copiar el vínculo, y personalizamos apropiadamente los mensajes. El correo electrónico incluirá un asunto y también puede tener un cuerpo más extenso con saltos de línea, imágenes y espacio en blanco. El texto deberá incluir un cuerpo más breve con saltos de línea, pero poco espacio en blanco y sin imágenes. Finalmente, la copia del vínculo no debe realizar otra acción que copiar el vínculo.
  • Usamos la IU compartida del sistema para todo lo demás, lo que incluye un mensaje de invitación corto que acompaña al vínculo.
  • Agregamos un vínculo directo a través de un esquema de URL o un vínculo universal a otra app que cuente con una lógica especial para manejar las invitaciones de tu app. Esto no funcionará fuera de una asociación entre tu organización y la otra app, y probablemente tampoco sea una opción para organizaciones más pequeñas. Sin embargo, es posible que algunas apps documenten públicamente su comportamiento de vinculación universal o directa. Implementaremos una versión de prueba de esto en la muestra.

Primero, define un tipo de contenido para invitaciones que resuma solo la información en una invitación y no incluya funciones. De esta forma, puedes empezar con los tipos de datos y pensar en tu código en términos de cómo esos datos se unen.

Swift

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

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

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

}

Kotlin

/**
 * 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
)

El único dato que se solicita aquí es la URL, ya que sin ella no puedes invitar a usuarios a tu app. Los otros datos se estructuran de manera clara para enviar correos electrónicos, lo que los hace un poco raros en algunos otros casos. Cuando se envía una invitación por mensaje de texto, la publicidad que acompaña al vínculo puede leerse de manera similar a un asunto de correo electrónico; sin embargo, cuando se comparte en las redes sociales el vínculo que acompaña el texto, este puede parecerse más a un cuerpo de correo electrónico. Tendrás que experimentar esto por tu cuenta a fin de encontrar el mejor balance para tu app y, si no estás seguro, siempre puedes usar un servicio como Remote Config para cambiar los valores del texto después de iniciarse la app.

Swift

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

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

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

}

Kotlin

/**
 * 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) {
        // ...
    }
}

Ahora, solo falta conectar este código a un componente de IU de tu elección. Revisa la implementación completa de este flujo de invitación en las muestras para iOS y Android en GitHub.

Todos estos métodos permiten a los usuarios enviar invitaciones a sus amigos, que, en definitiva, es la solución de invitación más básica. Muchas apps populares también envían invitaciones por correo electrónico con su propio backend, lo que requiere integrar un servicio de envío de correo, pero ofrece una cantidad de beneficios que de lo contrario no estarían disponibles con solo unas desventajas menores.

Ventajas:

  • Permite que el usuario no pueda modificar los correos electrónicos con lenguaje de marcado complejo antes de que se envíen.
  • Permite realizar más seguimiento o estadísticas detalladas (es decir, enviar respuestas satisfactorias y fallas sobre tu backend).

Desventajas:

  • Es más probable que los correos electrónicos se marquen como spam.
  • Requiere integración con un servicio de entrega de correo electrónico.
  • Requiere permisos de contactos en la app.

En general, enviar invitaciones mediante tu propio servicio de entrega de correos electrónicos proporciona una experiencia de invitación más consistente y potencialmente más enriquecida a costa de la versatilidad.

Abre el contenido del vínculo en la aplicación

Por último, necesitas recibir el vínculo que se le pasó a tu app para que esta pueda mostrarle el contenido pertinente al destinatario. Esto es fácil con el SDK de Dynamic Links:

iOS

Para recibir un Dynamic Link en iOS, debes implementar el método application:continueUserActivity:restorationHandler:. En el controlador de restablecimientos, puedes llamar a handleUniversalLink:completion: para obtener el Dynamic Link. Si se transfirió un Dynamic Link a tu app, puedes obtenerlo de la propiedad url de FIRDynamicLink. Por ejemplo:

Objective-C

[[FIRDynamicLinks dynamicLinks]
    handleUniversalLink:userActivity.webpageURL
             completion:^(FIRDynamicLink * _Nullable dynamicLink,
                          NSError * _Nullable error) {
      NSString *link = dynamicLink.url;
      BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
      // ...
    }];

Swift

FIRDynamicLinks.dynamicLinks()?.handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
    let link = dynamicLink.url
    let strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong
    // ...
}

Además, debes llamar a dynamicLinkFromCustomSchemeURL: en el método application:openURL:options: para recibir Dynamic Links que se pasaron a tu app como URL de esquemas personalizados. Por ejemplo:

Objective-C

FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink) {
  NSString *link = dynamicLink.url;
  BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
  // ...
  return YES;
}

Swift

let dynamicLink = FIRDynamicLinks.dynamicLinks()?.dynamicLinkFromCustomSchemeURL(url)
if let dynamicLink = dynamicLink {
  let link = dynamicLink.url
  let strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong
  // ...
  return true
}

Ahora que tienes el valor del parámetro link, puedes mostrarle el contenido del vínculo al usuario o procesar los datos que se especifican en el parámetro de otra manera. Una biblioteca de enrutamiento de URL como JLRoutes puede ayudarte con esta tarea.

Si recibes un vínculo dirigido a un destinatario específico, asegúrate de que el nivel de confianza del Dynamic Link sea strong antes de ejecutar código específico para ese usuario.

Android

En Android, debes usar el método getDynamicLink() para obtener los datos del Dynamic Link:

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

Kotlin

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

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

Ahora que tienes el valor del parámetro link, puedes mostrarle el contenido del vínculo al usuario o procesar los datos que se especifican en el parámetro de otra manera. Una biblioteca de enrutamiento de URL puede ayudarte con esta tarea.