Permite que los usuarios compartan el contenido de tu app para atraer usuarios nuevos

Una de las maneras más eficaces para lograr que los usuarios nuevos 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.

Cuando combinas la permanencia asociada a las referencias de usuarios 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 de tu app o publicar promociones en las que el referente y el referido se beneficien de forma mutua.

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 querían compartir con ellos. 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 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.

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. Dynamic Links te brinda la solución.

Por cada elemento de contenido que quieras que admita el uso compartido, crea un vínculo dinámico.

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 URLs 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 para computadoras. 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 incorporando 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, recomendamos que uses la API de acortamiento de URLs de Firebase Dynamic Links a fin de generar URLs más fáciles de leer para el usuario. Un Dynamic Link corto tiene el siguiente aspecto:

https://example.page.link/WXYZ

Cualquiera sea el vínculo que uses, cuando los usuarios abran el vínculo dinámico en su dispositivo, la app especificada por el parámetro apn (en Android) o los ibi y isi (en iOS) los llevará a 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.

Primero, observa este ejemplo simple de una app de chat basada en una 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 para compartir contenido

Android

captura de pantalla de app de chat captura de pantalla de app de chat con hoja para compartir contenido

Swift

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni 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

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni 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();
}

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

Swift

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni 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

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni 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"));
}

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 para compartir contenido

Android

captura de pantalla de referencia recompensada captura de pantalla de referencia recompensada con hoja para compartir contenido

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 para uso compartido 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 más que copiar el vínculo.
  • Para todo lo demás, usamos la IU del sistema para uso compartido, 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 encapsule solo la información de una invitación y no tenga funcionalidad alguna. 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

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni 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

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni 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) {
        // ...
    }

}

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 verse un poco raros en otros casos. Por ejemplo, cuando se envía una invitación por mensaje de texto, la publicidad que acompaña al vínculo puede leerse de manera similar al asunto de un 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 al cuerpo de un correo electrónico. Tendrás que experimentar esto por tu cuenta a fin de encontrar el mejor equilibrio 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

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni 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

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni 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) {
        // ...
    }

}

Ahora, solo falta conectar este código al componente de IU que quieras. Revisa la implementación completa de este flujo de invitación en las muestras para iOS y Android alojadas 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. Y las desventajas son mínimas.

Ventajas:

  • Permite crear correos electrónicos con lenguaje de marcado complejo que el usuario no podrá modificar antes de que se envíen.
  • Permite realizar más seguimiento o estadísticas detalladas (es decir, enviar información sobre procesos completos o con error en 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 vínculo dinámico a tu app, puedes obtenerlo de la propiedad url de FIRDynamicLink. Por ejemplo:

Objective‑C

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni watchOS.
[[FIRDynamicLinks dynamicLinks]
    handleUniversalLink:userActivity.webpageURL
             completion:^(FIRDynamicLink * _Nullable dynamicLink,
                          NSError * _Nullable error) {
      NSString *link = dynamicLink.url;
      BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
      // ...
    }];

Swift

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni watchOS.
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 URLs de esquemas personalizados. Por ejemplo:

Objective‑C

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni watchOS.
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink) {
  NSString *link = dynamicLink.url;
  BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
  // ...
  return YES;
}

Swift

Nota: Este producto de Firebase no se encuentra disponible en objetivos de macOS, Mac Catalyst, tvOS ni watchOS.
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 vínculo dinámico sea strong antes de ejecutar un código específico para ese usuario.

Android

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

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

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.