Google 致力于为黑人社区推动种族平等。查看具体举措
Эта страница переведена с помощью Cloud Translation API.
Switch to English

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

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

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

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

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

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

Настройте новый проект Firebase и установите SDK Dynamic Links в свое приложение.

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

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

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

При создании динамической ссылки вам необходимо указать URL-адрес HTTP или HTTPS в качестве параметра 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

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

https://example.page.link/WXYZ

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

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

iOS

chat app screenshotchat app screenshot with share sheet

Android

chat app screenshotchat app screenshot with share sheet

Быстрый

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

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

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

Быстрый

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

- (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-адреса или универсальную ссылку на другое приложение, которое имеет особую логику для обработки приглашений вашего приложения. Это не будет работать без партнерства между вашей организацией и другим приложением и, вероятно, не подходит для небольших организаций. Тем не менее, некоторые приложения могут публично документировать свое поведение универсальных / глубоких ссылок. Мы реализуем фиктивную версию этого в нашем примере.

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

Быстрый

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

/// 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, чтобы вы могли изменять текстовые значения после запуска приложения.

Быстрый

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

/// 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 для iOS и Android .

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

Плюсы:

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

Минусы:

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

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

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

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

iOS

В iOS вы получаете динамическую ссылку, реализуя метод application:continueUserActivity:restorationHandler: . В обработчике восстановления вы можете получить динамическую ссылку, вызвав handleUniversalLink:completion: Если вашему приложению была передана динамическая ссылка, вы можете получить ее из свойства url FIRDynamicLink . Например:

Цель-C

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

Быстрый

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

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

Цель-C

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

Быстрый

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() для получения данных из динамической ссылки:

Ява

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-маршрутизации может помочь с этой задачей.