Catch up on everything we announced at this year's Firebase Summit. Learn more

Пригласите пользователей в ваше приложение

Один из наиболее эффективных способов побудить новых пользователей установить ваше приложение - позволить вашим пользователям делиться контентом из вашего приложения со своими друзьями. С помощью динамических ссылок вы можете создать отличную среду обмена между пользователями: пользователи, которые получают рекомендации по контенту от своих друзей, могут щелкнуть ссылку и перейти непосредственно к общему контенту в вашем приложении, даже если им нужно перейти в приложение. Store или Google Play Store, чтобы сначала установить приложение.

Комбинируя прилипчивость рефералов пользователей и постоянство динамических ссылок, вы можете создавать функции обмена и рефералов между пользователями, которые привлекают новых пользователей, привлекая их непосредственно к контенту вашего приложения или предлагая рекламные акции, которые взаимно выгодны рефералу и рефералу. .

Ключевые преимущества

  • Новые пользователи, впервые открывающие ваше приложение, получают индивидуальный опыт первого запуска, контекстуализированный на основе того, чем их друг хотел с ними поделиться. Например, вы можете отобразить контент, которым с ними поделились, или автоматически связать их с другом, который их пригласил.
  • Позволяет пользователям легко делиться контентом со своими друзьями на разных платформах, независимо от того, установлено ли у их друзей ваше приложение.

Вот как начать!

Настройка нового Firebase проекта и установить динамические ссылки SDK в приложение.

Установка SDK динамических ссылок позволяет Firebase передавать данные о динамической ссылке в приложение, в том числе после того, как пользователь установит приложение.

Пришло время настроить ссылки, которые пользователи могут отправлять своим друзьям. Не волнуйтесь, если у друзей ваших пользователей еще не установлено приложение; Динамические ссылки могут позаботиться об этом за вас.

Для каждого элемента контента , который вы хотите быть разделяемыми, создать Dynamic Link .

При создании Dynamic Link, вам необходимо предоставить HTTP или HTTPS URL как link параметра , который будет использоваться для идентификации контента , которые вы обмена вы. Если у вас есть веб-сайт с аналогичным содержанием, вам следует использовать URL-адреса своего веб-сайта. Это обеспечит правильное отображение этих ссылок на платформе, не поддерживающей динамические ссылки, например на настольном браузере. Например:

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

Вы также можете добавить дополнительную информацию в полезные данные, добавив параметры в кодировке URL - например, чтобы указать, что ссылка предназначена для определенного пользователя, например, в приглашении к игре.

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

Перед тем, как поделиться этими ссылками, вы можете захотеть использовать Shortener API Firebase Dynamic ссылки URL для создания безвредной перспективной URL. Коротенькие Dynamic Link выглядит как в следующем примере:

https://example.page.link/WXYZ

Какой бы ни ссылка , которую вы используете, когда пользователи открыть Dynamic Link на устройстве, приложение задается apn параметром (на Android) или ibi и isi параметров (КСН) будет принимать пользователей к Play или магазина App Store , чтобы установить приложение если он еще не установлен. Затем, когда приложение установлено и открыто, URL-адрес, указанный в параметре link, передается приложению.

Во-первых, взгляните на этот простой пример приложения для чата на основе комнаты, такого как Hangouts, которое генерирует ссылки для приглашения людей в комнаты чата.

iOS

chat app screenshotchat app screenshot with share sheet

Android

chat app screenshotchat app screenshot with share sheet

Быстрый

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели 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
}

Цель-C

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели 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;
}

Джава

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

Котлин + 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
}

Если у вас есть динамическая ссылка, вы можете добавить кнопку общего доступа к своему пользовательскому интерфейсу, которая запустит стандартный поток обмена платформой:

Быстрый

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели 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)
}

Цель-C

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели 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];
}

Джава

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

Котлин + 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"))
}

В этом примере пользовательский интерфейс общего доступа по умолчанию автоматически представляет список приложений для обмена ссылкой, поэтому вы можете настроить его в своем собственном приложении с помощью всего нескольких строк кода.

Вместо того, чтобы предлагать пользователю выбирать контакты и составлять сообщение в вашем приложении, эти действия делегируются приложению, которое они выбирают из диалогового окна общего доступа. Кроме того, делегирование совместного использования другим приложениям означает, что вам не нужно запрашивать у пользователя разрешения для контактов, и позволяет пользователям выбирать из расширенного списка контактов в выбранном ими приложении. Для того, чтобы более эффективно содействовать социальному обмену, вы можете добавить метаданные просмотра социальных медиа для вашей динамической связи , которая будет отображаться вместе со ссылкой на основных социальных каналов.

Иногда, однако, простой отправки простой ссылки без текста недостаточно для убедительного перехода. Сопровождая ссылку коротким сообщением и, если возможно, более подробным изложением, пользователи могут понять ценностное предложение реферала, когда они его получат:

iOS

rewarded referral screenshotrewarded referral screenshot with share sheet

Android

rewarded referral screenshotrewarded referral screenshot with share sheet

Хотя это более сложный, чем последний пример, подход будет более или менее таким же. На этом экране есть большая графика с ценностным предложением приглашения и кнопками для публикации в основных социальных сетях. В этом потоке пользовательского интерфейса есть некоторая избыточность - некоторые каналы совместного использования представлены индивидуально, что позволяет более индивидуально настраивать сообщения, например добавлять строку темы в приглашения по электронной почте. В этом меню приглашений мы:

  • Представьте кнопки отправки электронной почты, текстового сообщения и копирования ссылки, а также соответствующим образом настройте их сообщения. Электронное письмо будет включать тему и может включать более длинный текст с разрывами строк, изображениями и пробелами; текст должен включать более короткий текст с разрывами строк, но с небольшим количеством пробелов и без изображений; и копирование ссылки должно просто копировать ссылку и ничего больше.
  • Используйте пользовательский интерфейс общего доступа к системе для всего остального, включая короткое сообщение-приглашение, сопровождающее ссылку.
  • Глубинная ссылка через схему URL-адреса или универсальную ссылку на другое приложение, которое имеет особую логику для обработки приглашений вашего приложения. Это не будет работать без партнерства между вашей организацией и другим приложением и, вероятно, не подходит для небольших организаций. Тем не менее, некоторые приложения могут публично документировать свое поведение универсальных / глубоких ссылок. Мы реализуем фиктивную версию этого в нашем примере.

Во-первых, определите тип контента приглашения, который инкапсулирует только информацию в приглашении и не содержит никаких функций. Таким образом, вы можете начать с типов данных и подумать о своем коде с точки зрения того, как он объединяет эти данные.

Быстрый

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели 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

}

Цель-C

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели 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

Джава

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

}

Котлин + 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
)

Единственная необходимая часть данных - это URL-адрес, без которого вы не сможете приглашать пользователей в свое приложение. Остальные данные четко структурированы для отправки электронных писем, что делает их немного неудобными в некоторых других случаях - при отправке приглашения по тексту рекламное объявление, сопровождающее ссылку, может читаться аналогично теме электронного письма, но при отправке в социальные сети сопроводительный текст ссылки может быть больше похож на тело письма. Вы должны будете экспериментировать с этим самостоятельно , чтобы найти лучший баланс для вашего приложения, и если вы не уверены, вы всегда можете использовать услугу , как Remote Config , чтобы позволить вам изменить текстовые значения после запуска приложения.

Быстрый

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели 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()

}

Цель-C

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели 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

Джава

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

}

Котлин + 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) {
        // ...
    }
}

Теперь все, что осталось, - это подключить это к любому компоненту пользовательского интерфейса по вашему выбору. Для полного осуществления этого пригласит поток, см образцы на GitHub для прошивки и Android .

Все это методы, позволяющие вашим пользователям отправлять приглашения своим друзьям, что является наиболее легким решением для приглашения. Многие популярные приложения также доставляют приглашения, отправляя электронные письма через свой собственный сервер, что требует интеграции службы отправки почты, но предлагает ряд преимуществ, которые в противном случае недоступны с несколькими незначительными недостатками.

Плюсы:

  • Включает электронные письма со сложной разметкой, которую пользователь не может изменить перед отправкой.
  • Обеспечивает более детальное отслеживание / аналитику (например, отправка успешных и неудачных результатов на ваш сервер).

Минусы:

  • Письма с большей вероятностью будут отмечены как спам
  • Требуется интеграция со службой доставки электронной почты
  • Требуются разрешения для контактов в приложении

Как правило, отправка приглашений через вашу собственную службу доставки электронной почты обеспечивает более последовательный и потенциально более богатый опыт приглашения за счет универсальности.

Откройте связанный контент в вашем приложении

Наконец, вам нужно получить ссылку, которая передается в ваше приложение, чтобы вы могли отображать связанный контент для получателя. Это легко сделать с помощью SDK динамических ссылок:

iOS

КСН, вы получите Dynamic Link, реализовав application:continueUserActivity:restorationHandler: метод. В обработчике восстановления, вы можете получить Dynamic Link по телефону handleUniversalLink:completion: . Если Dynamic Link был передан в приложение, вы можете получить его из url - FIRDynamicLink url собственности FIRDynamicLink . Например:

Цель-C

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели watchOS.
[[FIRDynamicLinks dynamicLinks]
    handleUniversalLink:userActivity.webpageURL
             completion:^(FIRDynamicLink * _Nullable dynamicLink,
                          NSError * _Nullable error) {
      NSString *link = dynamicLink.url;
      BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
      // ...
    }];

Быстрый

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели watchOS.
FIRDynamicLinks.dynamicLinks()?.handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
    let link = dynamicLink.url
    let strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong
    // ...
}

Кроме того, вы должны вызвать dynamicLinkFromCustomSchemeURL: в application:openURL:options: метод получения динамической ссылки передаются в приложение как пользовательские схемы URL. Например:

Цель-C

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели watchOS.
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink) {
  NSString *link = dynamicLink.url;
  BOOL strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong;
  // ...
  return YES;
}

Быстрый

Примечание: Этот продукт Firebase не доступен на MacOS, Mac Catalyst, tvOS или цели watchOS.
let dynamicLink = FIRDynamicLinks.dynamicLinks()?.dynamicLinkFromCustomSchemeURL(url)
if let dynamicLink = dynamicLink {
  let link = dynamicLink.url
  let strongMatch = dynamicLink.matchConfidence == FIRDynamicLinkMatchConfidenceStrong
  // ...
  return true
}

Теперь, когда у вас есть значение link параметра можно отобразить связанное содержимое получателю или обрабатывать данные , указанные в параметре каким - либо другим способом. URL-адреса , маршрутизации библиотеки , такие как JLRoutes может помочь в решении этой задачи.

Если вы получаете ссылку , предназначенную для конкретного получателя, убедитесь , что доверие матча в Dynamic Link является strong перед запуском любой пользователь-специфической логики.

Android

В Android вы используете getDynamicLink() метод , чтобы получить данные от Dynamic Link:

Джава

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

Котлин + KTX

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

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

Теперь, когда у вас есть значение link параметра можно отобразить связанное содержимое получателю или обрабатывать данные , указанные в параметре каким - либо другим способом. Библиотека URL-маршрутизации может помочь с этой задачей.