Flutter
Пакет unolink — это тонкий слой поверх нативных SDK для iOS и Android, которые поставляются внутри него. Ему не нужны
разрешения кроме доступа в интернет и записи в Info.plist. Опубликован на pub.dev издателем unolink.dev. Тариф Pro и выше.
Требования
- Flutter 3.22+ (Dart 3.4+).
- Android 6.0+ (
minSdk 23) и iOS 13+. - Ключ SDK: в панели откройте приложение → Настройки → Ключи SDK → Новый ключ. Он показывается один раз, поэтому скопируйте его сразу.
Установка
flutter pub add unolink
Это добавит unolink: ^0.3.3 в pubspec.yaml и загрузит пакет. После этого пересоберите приложение; после добавления нативного
кода hot reload недостаточно.
Если CocoaPods падает при сборке iOS с ошибкой кодировки (Ruby 4 или локаль не в UTF-8), запустите его сами в UTF-8, а затем соберите снова:
cd ios && LANG=en_US.UTF-8 pod install
Настройка
Вызовите configure один раз в main(), после WidgetsFlutterBinding.ensureInitialized() и до runApp:
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:unolink/unolink.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Unolink.configure('ulk_…', debug: kDebugMode);
runApp(const MyApp());
}
Параметры
| Параметр | По умолчанию | Что делает |
|---|---|---|
debug | false | Помечает эту установку как тестовое устройство. Передавайте kDebugMode. Панели скрывают тестовые устройства, если не включено Учитывать тестовые устройства. |
logLevel | UnolinkLogLevel.warn | Сколько выводится в консоль Xcode или Logcat (тег Unolink): none, error, warn, info, debug. |
baseUrl | https://api.unolink.dev | SDK API. Оставьте как есть. |
Ключ публичный: он поставляется внутри вашего приложения и может отправлять данные только для этого одного приложения. См. Ключи SDK.
События воронки
Добавьте по одной строке в каждый важный момент. Они станут шагами в Воронке и «Путях».
Unolink.onboardingCompleted(); // the last onboarding screen is done
Unolink.paywallViewed(placement: 'onboarding'); // a paywall appeared; placement says which one
Unolink.paywallSkipped(placement: 'onboarding'); // closed without buying
Unolink.signUp(method: 'apple'); // an account was created
Unolink.signUpSkipped(); // went on as a guest (0.3.2+)
Без RevenueCat сообщайте о пробных периодах и покупках сами. Сумма передаётся строкой, поэтому она никогда не округляется:
Unolink.trialStarted(productId: 'pro_yearly');
Unolink.purchase('49.99', 'USD', productId: 'pro_yearly');
Unolink.purchaseCancelled(productId: 'pro_yearly'); // closed the purchase sheet
Unolink.purchaseFailed(productId: 'pro_yearly', reason: 'payment_failed');
Ваши собственные события принимают имя и до 20 свойств:
Unolink.track('level_up', {'level': 3});
Полный список с названиями, которые попадают в панель, — в разделе События.
ID пользователя и RevenueCat
Если вы используете RevenueCat, подключите его в приложении → Настройки → RevenueCat. Тогда не
вызывайте purchase и trialStarted: RevenueCat сам отправляет пробные периоды, покупки, продления, отмены и возвраты, а
Unolink игнорирует вызовы покупок из приложения, чтобы ничего не учитывалось дважды.
Чтобы привязать эти покупки к установке, сообщайте собственный app user ID RevenueCat. В SDK 0.3.2 и новее одна строка
поддерживает его в актуальном состоянии. Вызовите её один раз при запуске, до или после configure:
Unolink.connectRevenueCat(
() => Purchases.appUserID,
addListener: Purchases.addCustomerInfoUpdateListener,
removeListener: Purchases.removeCustomerInfoUpdateListener,
);
Unolink считывает ID после настройки, при каждом обновлении данных клиента (покупки, logIn, logOut) и каждый раз, когда
приложение возобновляется, и отправляет его, только если он изменился. Если RevenueCat ещё не настроен, чтение тихо завершается
неудачей и повторяется позже. Вызов возвращает функцию для отключения. Поэтому на Flutter Unolink.revenueCatUserChanged() обычно не нужен.
Без этого (или до версии 0.3.2) вызывайте setUserId с ID из RevenueCat после Purchases.configure, после каждого
Purchases.logIn и Purchases.logOut и при каждом запуске. Используйте что-то одно, а не оба способа сразу:
// after Purchases.configure, logIn and logOut, and on every launch
Unolink.setUserId(await Purchases.appUserID);
Для гостя это анонимный ID RevenueCat, поэтому покупка, сделанная до регистрации, сразу привязывается к установке.
После logIn это ID аккаунта. Учитываются все ID, которые сообщала установка, поэтому покупка гостя остаётся привязанной.
См. Гости и аккаунты.
Unolink никогда не хранит сам ID, только односторонний хеш, который у каждого вашего приложения свой.
Отложенные диплинки
На Android, когда человек устанавливает приложение по ссылке Unolink с диплинком, слушатель срабатывает один раз, при первом открытии. На iPhone он не вызывается: у Apple нет реферера установки, а Unolink никогда не использует фингерпринтинг.
Unolink.setDeferredDeepLinkListener((link) {
// link.deepLink: '/promo/3for2', link.params: {'offer': '3for2'}
// link.linkSlug: 'tiktok' or null, link.clickId: 'clk_01JA…'
if (link.deepLink != null) router.go(link.deepLink!);
Unolink.consumeDeferredDeepLink();
});
Слушатель вызывается один раз на установку. Ссылка, пришедшая до того, как вы его задали, доставляется, когда вы его зададите.
Откройте её после онбординга
Первое открытие обычно начинается с онбординга. Если экран ссылки находится за онбордингом или входом в аккаунт, не открывайте его из слушателя. Когда онбординг (или вход) завершён, прочитайте ожидающую ссылку, откройте её, а затем отметьте как использованную:
// when onboarding (or sign-in) is done, and on every launch after that until it's consumed
final link = await Unolink.getPendingDeferredDeepLink();
if (link?.deepLink != null) {
router.go(link!.deepLink!);
await Unolink.consumeDeferredDeepLink();
}
Ссылка ждёт, пока вы её не используете, даже если приложение за это время закрывали (до 30 дней после установки; 0.3.3+).
Новый пользователь, который бросил онбординг на середине, всё равно получит её при следующем запуске, так что хранить её самим не нужно.
Вызовите consumeDeferredDeepLink(), когда откроете её: до этого getPendingDeferredDeepLink() возвращает её при каждом
запуске. Он возвращает null до configure и пока Google Play не ответил, а на iPhone всегда null.
Задайте Диплинк и Параметры ссылки в панели (Ссылки → ⋯ → Изменить). Как это работает, описано в разделе Отложенные диплинки на Android.
Другие вызовы
| Вызов | Что делает |
|---|---|
await Unolink.getInstallId() | Случайный ID этой установки или null до configure. Он не идентифицирует ни человека, ни устройство. |
Unolink.flush() | Отправляет события из очереди прямо сейчас. Обычно не нужен. |
Unolink.setEnabled(false) | Отключает отслеживание и удаляет события из очереди, для вашей настройки отказа. true включает его снова. |
Тестовые устройства
С debug: kDebugMode debug-сборки считаются тестовыми устройствами. Их данные настоящие, но скрыты, пока вы не включите Включать
тестовые устройства в Воронке и «Путях». Подробнее в разделе Тестирование.
Конфиденциальность
- Без IDFA, без Google Advertising ID, без запроса App Tracking Transparency, без фингерпринтинга.
- Случайный ID установки, версия приложения, версия ОС, версия SDK, телефон или планшет, язык. Страна определяется на границе сети. IP-адреса никогда не хранятся.
- На iOS манифест конфиденциальности нативного SDK входит в пакет: аналитика, не связанная с личностью.
- Никогда не передавайте имена, email или другие персональные данные в свойствах событий.
Решение проблем
- MissingPluginException? Остановите приложение и запустите его снова. Hot reload и hot restart не загружают новый нативный код.
- В панели ничего нет? Включите Учитывать тестовые устройства: сборки с
kDebugModeпо умолчанию скрыты. - Всё равно ничего? Настройте с
logLevel: UnolinkLogLevel.debugи ищитеUnolinkв консоли Xcode или Logcat. Неверный или отозванный ключ записывается в лог как ошибка.
Подробнее в разделе Решение проблем.