Краткий обзор. Интегрируйте SDK AppsFlyer в приложения для iOS, чтобы измерять установки, внутренние события, медиа-источники и другие показатели.
Примечания о выпуске (до версии 6.2.4)
Примечание
- iOS SDK V5.4.4 полноценно работает на устройствах iOS 14. Тем не менее мы рекомендуем интегрировать SDK V6.X, чтобы обеспечить совместимость с будущими выпусками iOS. См. раздел Обновление до iOS SDK V6.
- Атрибуция Apple App Clips доступна, начиная с SDK V6.0.8. Подробные сведения см. в нашем руководстве по App Clips для разработчиков.
- По заявлениям компании Apple, внедрение фреймворка App Tracking Transparency (ATT) планируется начать с iOS 14.5 (т. е. в начале весны 2021 года). Узнайте, как настроить поддержку ATT в SDK для iOS.
1. Обзор
SDK позволяет регистрировать установки приложений и события. Это надежный и безопасный SDK, который не требует больших ресурсов и очень просто встраивается.
Вы можете регистрировать установки приложения, обновления, сессии и внутренние события (покупки из приложения, уровни игры и др.), что позволяет оценить ROI и уровень вовлеченности пользователей.
Версия iOS | Поддерживаемые модели атрибуции |
---|---|
8–11.3 |
|
11.3–13 |
|
14+ |
|
* iOS SDK V5.4 и более ранние версии:
|
1.1 Интеграция SDK — порядок выполнения
Вкладка | Цель | Результат |
---|---|---|
Интеграция SDK |
Как добавить и сконфигурировать SDK. |
|
Основные API |
Как использовать основные API SDK:
|
На панели управления отображаются данные о внутренних событиях приложения и доходах. Возможность выполнять диплинкинг. |
Как использовать дополнительные API:
|
Вы можете измерять количество удалений, рефералы и степень вовлечения пользователей с использованием push-уведомлений, отрабатывать сценарии защиты персональных данных пользователей, и многое другое. |
|
Справочник для разработчиков по методам SDK |
|
1.2 Совместимость SDK
SDK AppsFlyer для iOS совместим со следующими платформами:
- iOS
8
+ (iPhone, iPod, iPad) - tvOS
9
+ (Apple TV) - Совместим с сетями Apple IPv6 DNS64/NAT64
Эта вкладка содержит описание процедур внедрения и инициализации SDK и предназначена для разработчиков приложений. После выполнения описанных здесь действий на дэшборде вашего приложения отобразятся две установки, органическая и неорганическая.
2. Добавьте SDK в ваше приложение
2.1 Загрузка и добавление SDK в Xcode
- Скачайте и установите последнюю версию CocoaPods.
- Добавьте следующую строку в
Podfile
:
pod 'AppsFlyerFramework'
- Запустите
pod install
. - Используйте файл
.xcworkspace
, а не.xcodeproj
, чтобы открывать проект в Xcode.
Примечание
Если вы разрабатываете приложение для tvOS, CocoaPods автоматически добавляет соответствующие зависимости из AppsFlyerFramework.
- Установите последнюю версию Carthage.
- В файл Cartfile добавьте следующую строку:
https://raw.githubusercontent.com/AppsFlyerSDK/AppsFlyerFramework/master/Carthage/appsflyer-ios.json
Примечание
Ссылка выше ведет на статическую библиотеку. Если вы обновляетесь до более новой версии iOS, сделайте следующее:
- Удалите из Xcode стадию Run Script (Запуск сценария), которая запускает фреймворки копирования copy-frameworks.
- Убедитесь, что библиотека не встроена.
Подробнее читайте в статье о Carthage.
В настоящее время не поддерживает приложения tvOS.
-
Загрузите SDK для iOS как static framework.
Для проверки целостности загруженной статической структуры SDK нажмите здесь. - Распакуйте загруженный файл AppsFlyerLib.framework.zip
- Перетащите файл AppsFlyerLib.framework в свой проект в Xcode.
- Установите флажок Copy items if needed (Копировать элементы при необходимости).
Примечание
Этот способ подходит только для iOS 8 и более новых версий.
Для приложений tvOS вам нужен другой AppsFlyerFramework:
- Клонируйте этот репозиторий.
- Найдите AppsFlyerLib.framework в этой папке клонированного репозитория.
- Повторите шаги 3 и 4.
2.2 Зависимости собственных фреймворков iOS
Этот SDK автоматически добавляет и использует следующие нативные фреймворки:
- AdSupport.framework
- Эта инфраструктура необходима для сбора идентификаторов IDFA на устройствах.
Без IDFA невозможно атрибутировать установки, выполненные в Facebook Ads, Twitter, Google Рекламе и других сетях. - iAd.framework
- Измерение эффективности кампаний Apple Search Ads в вашем приложении.
- AdServices Framework (
V6.1.3+
) - Измерение эффективности кампаний Apple Search Ads в вашем приложении.
Если вы хотите убрать эти фреймворки и отключить сбор IDFA:
- Отключите сбор данных IDFA
- Отключите iAd.framework
Строгий режим в SDK
Используйте строгий режим в SDK, чтобы полностью удалить функции сбора IDFA и зависимости инфраструктуры AdSupport (например, при разработке приложений для детей).
Примечание. Данные IDFV остаются доступны.
В вашем Podfile
замените зависимость AppsFlyerLib
на:
pod 'AppsFlyerFramework/Strict','6.2.3'
Примечание. Если вы используете строгий режим в SDK и вызываете disableAdvertisingIdentifier
, возникнет ошибка компиляции.
Примечание
Если вы используете SDK версии 4.10.4 или ранее, нужно добавлять фреймворки для поддержки рекламы вручную.
Чтобы добавить фреймворки для поддержки рекламы вручную:
- В вашем проекте Xcode выберите цель проекта.
- Выберите вкладку General для вашей цели.
- Раскройте раздел Linked Frameworks and Libraries.
- Нажмите +, чтобы добавить фреймворк.
- Введите в поле поиска AdSupport.framework
- Выберите из списка AdSupport.framework.
Повторите те же шаги для iAd.framework.
3. Внедрение и инициализация SDK
В этом разделе описана процедура инициализации и запуска SDK AppsFlyer для iOS.
3.1 Получение ключа разработчика AppsFlyer (dev key)
AppsFlyer использует ключ разработчика в качестве уникального идентификатора вашего аккаунта. Ключ разработчика является обязательным, поскольку он позволяет SDK безопасно отправлять и получать данные, которые относятся к вашему аккаунту.
Чтобы получить ключ разработчика:
- В AppsFlyer перейдите в раздел Configuration (Конфигурация) > App Settings (Настройки приложения).
- Скопируйте свой ключ разработчика, он понадобится вам на следующем шаге.
3.2 Инициализация SDK
Примечание
Информацию о поддержке приложений iOS, использующих SceneDelegate
, см. в разделе Инициализация SDK с помощью SceneDelegate.
Следующий код приведен как пример реализации. Не забудьте заменить маркеры-заполнители <AF_DEV_KEY>
и <APPLE_APP_ID>
соответствующими значениями.
В файле AppDelegate.h
:
- Импортируйте заголовок
AppsFlyerLib/AppsFlyerLib.h
. - Добавьте
AppsFlyerLibDelegate
в объявление интерфейсаAppDelegate
.
#import <UIKit/UIKit.h>
#import <AppsFlyerLib/AppsFlyerLib.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, AppsFlyerLibDelegate>
@end
Импортируйте в файл AppDelegate.m
такую строку:
- В методе
didFinishLaunchingWithOptions
укажите:- Ключ разработчика AppsFlyer, который вы скопировали в предыдущем шаге
- Идентификатор приложения Apple
- Для сбора IDFA настройте поддержку App Tracking Transparency (ATT).
- Дополнительные настройки
- Переопределите обратные вызовы
onConversionDataSuccess
иonConversionDataFail
для обработки конверсий и активации отложенного диплинкинга. - Переопределите обратные вызовы
onAppOpenAttribution
иonAppOpenAttributionFailure
для обработки атрибуции и активации прямого диплинкинга. - В обратном вызове
didReceiveRemoteNotification
вызовите методhandlePushNotification
для атрибуции повторных вовлечений, полученных при помощи push-уведомлений. - В обратном вызове
applicationDidBecomeActive
вызовитеstart
.
#import "AppDelegate.h"
#import <UserNotifications/UserNotifications.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
/** APPSFLYER INIT **/
[AppsFlyerLib shared].appsFlyerDevKey = @"<AF_DEV_KEY>";
[AppsFlyerLib shared].appleAppID = @"<APPLE_APP_ID>";
[AppsFlyerLib shared].delegate = self;
/* Set isDebug to true to see AppsFlyer debug logs */
[AppsFlyerLib shared].isDebug = true;
if (@available(iOS 10, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
} else {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes: UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
return YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[AppsFlyerLib shared] start];
}
// Deep linking
// Open URI-scheme for iOS 9 and above
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *) options {
[[AppsFlyerLib shared] handleOpenUrl:url options:options];
return YES;
}
// Open URI-scheme for iOS 8 and below
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation {
[[AppsFlyerLib shared] handleOpenURL:url sourceApplication:sourceApplication withAnnotation:annotation];
return YES;
}
// Open Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
[[AppsFlyerLib shared] continueUserActivity:userActivity restorationHandler:restorationHandler];
return YES;
}
// Report Push Notification attribution data for re-engagements
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[[AppsFlyerLib shared] handlePushNotification:userInfo];
}
// AppsFlyerLib implementation
//Handle Conversion Data (Deferred Deep Link)
-(void)onConversionDataSuccess:(NSDictionary*) installData {
id status = [installData objectForKey:@"af_status"];
if([status isEqualToString:@"Non-organic"]) {
id sourceID = [installData objectForKey:@"media_source"];
id campaign = [installData objectForKey:@"campaign"];
NSLog(@"This is a non-organic install. Media source: %@ Campaign: %@",sourceID,campaign);
} else if([status isEqualToString:@"Organic"]) {
NSLog(@"This is an organic install.");
}
}
-(void)onConversionDataFail:(NSError *) error {
NSLog(@"%@",error);
}
//Handle Direct Deep Link
- (void) onAppOpenAttribution:(NSDictionary*) attributionData {
NSLog(@"%@",attributionData);
}
- (void) onAppOpenAttributionFailure:(NSError *)error {
NSLog(@"%@",error);
}
@end
В файле AppDelegate.swift
:
- import
AppsFlyerLib
- Добавьте
AppsFlyerLibDelegate
в объявление классаAppDelegate
. - В методе
didFinishLaunchingWithOptions
укажите:- Ключ разработчика AppsFlyer
- Идентификатор приложения
- Для сбора IDFA настройте поддержку App Tracking Transparency (ATT).
- Дополнительные настройки
- Переопределите обратные вызовы
onConversionDataSuccess
иonConversionDataFail
для обработки конверсий и активации отложенного диплинкинга. - Переопределите обратные вызовы
onAppOpenAttribution
иonAppOpenAttributionFailure
для обработки атрибуции и активации прямого диплинкинга. - В обратном вызове
didReceiveRemoteNotification
вызовите методhandlePushNotification
для атрибуции повторных вовлечений, полученных при помощи push-уведомлений. - В обратном вызове
applicationDidBecomeActive
вызовитеstart
.
import UIKit
import AppsFlyerLib
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let defaults = UserDefaults.standard
//MARK: LifeCycle
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
AppsFlyerLib.shared().appsFlyerDevKey = "<AF_DEV_KEY>"
AppsFlyerLib.shared().appleAppID = "<APPLE_APP_ID>"
AppsFlyerLib.shared().delegate = self
AppsFlyerLib.shared().isDebug = true
// iOS 10 or later
if #available(iOS 10, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { _, _ in }
application.registerForRemoteNotifications()
}
// iOS 9 support - Given for reference. This demo app supports iOS 13 and above
else {
application.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
application.registerForRemoteNotifications()
}
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Start the SDK (start the IDFA timeout set above, for iOS 14 or later)
AppsFlyerLib.shared().start()
}
// Open Univerasal Links
// For Swift version < 4.2 replace function signature with the commented out code:
// func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print(" user info \(userInfo)")
AppsFlyerLib.shared().handlePushNotification(userInfo)
}
// Open Deeplinks
// Open URI-scheme for iOS 8 and below
private func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
AppsFlyerLib.shared().continue(userActivity, restorationHandler: restorationHandler)
return true
}
// Open URI-scheme for iOS 9 and above
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
AppsFlyerLib.shared().handleOpen(url, sourceApplication: sourceApplication, withAnnotation: annotation)
return true
}
// Report Push Notification attribution data for re-engagements
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
AppsFlyerLib.shared().handleOpen(url, options: options)
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
AppsFlyerLib.shared().handlePushNotification(userInfo)
}
// Reports app open from deep link for iOS 10 or later
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
return true
}
}
//MARK: AppsFlyerLibDelegate
extension AppDelegate: AppsFlyerLibDelegate{
// Handle Organic/Non-organic installation
func onConversionDataSuccess(_ installData: [AnyHashable: Any]) {
print("onConversionDataSuccess data:")
for (key, value) in installData {
print(key, ":", value)
}
if let status = installData["af_status"] as? String {
if (status == "Non-organic") {
if let sourceID = installData["media_source"],
let campaign = installData["campaign"] {
print("This is a Non-Organic install. Media source: \(sourceID) Campaign: \(campaign)")
}
} else {
print("This is an organic install.")
}
if let is_first_launch = installData["is_first_launch"] as? Bool,
is_first_launch {
print("First Launch")
} else {
print("Not First Launch")
}
}
}
func onConversionDataFail(_ error: Error) {
print(error)
}
//Handle Deep Link
func onAppOpenAttribution(_ attributionData: [AnyHashable : Any]) {
//Handle Deep Link Data
print("onAppOpenAttribution data:")
for (key, value) in attributionData {
print(key, ":",value)
}
}
func onAppOpenAttributionFailure(_ error: Error) {
print(error)
}
}
3.2.1 Инициализация SDK с помощью SceneDelegate
Применяйте данный метод инициализации только при использовании SceneDelegate
.
При использовании SceneDelegate
метод applicationDidBecomeActive
не применяется, поэтому вместо него для инициализации SDK следует использовать обходное решение UIApplicationDidBecomeActiveNotification
, как показано в следующем примере.
Следующий код приведен как пример реализации. Не забудьте заменить маркеры-заполнители <AF_DEV_KEY>
и <APPLE_APP_ID>
соответствующими значениями.
В файле AppDelegate.h
:
- Импортируйте заголовок
AppsFlyerLib/AppsFlyerLib.h
. - Добавьте
AppsFlyerLibDelegate
в объявление интерфейсаAppDelegate
.
#import <AppsFlyerLib/AppsFlyerLib.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, AppsFlyerLibDelegate>
@end
Импортируйте в файл AppDelegate.m
такую строку:
- В обратном вызове
didFinishLaunchingWithOptions
укажите:- Ключ разработчика AppsFlyer
- Идентификатор приложения
- Для сбора IDFA настройте поддержку App Tracking Transparency (ATT).
- Дополнительные настройки
- Переопределите обратные вызовы
onConversionDataSuccess
иonConversionDataFail
для обработки конверсий и активации отложенного диплинкинга. - Переопределите обратные вызовы
onAppOpenAttribution
иonAppOpenAttributionFailure
для обработки атрибуции и активации прямого диплинкинга. - В обратном вызове
didReceiveRemoteNotification
вызовите методhandlePushNotification
для атрибуции повторных вовлечений, полученных при помощи push-уведомлений. - В обратном вызове
sendLaunch
вызовитеstart
.
#import "AppDelegate.h"
#import <AppsFlyerLib/AppsFlyerLib.h>
#import <UserNotifications/UserNotifications.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
// Start the AppsFlyer SDK
- (void)sendLaunch:(UIApplication *)application {
[[AppsFlyerLib shared] start];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
/** APPSFLYER INIT **/
[AppsFlyerLib shared].appsFlyerDevKey = @"<AF_DEV_KEY>";
[AppsFlyerLib shared].appleAppID = @"<APPLE_APP_ID>";
[AppsFlyerLib shared].delegate = self;
/* Задайте для isDebug значение true, чтобы просмотреть журналы отладки AppsFlyer */
[AppsFlyerLib shared].isDebug = true;
// Используйте UIApplicationDidBecomeActiveNotification для запуска SDK
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sendLaunch:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
if (@available(iOS 10, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
} else {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes: UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
return YES;
}
// Report Push Notification attribution data for re-engagements
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[[AppsFlyerLib shared] handlePushNotification:userInfo];
}
// AppsFlyerLib implementation
//Handle Conversion Data (Deferred Deep Link)
-(void)onConversionDataSuccess:(NSDictionary*) installData {
id status = [installData objectForKey:@"af_status"];
if([status isEqualToString:@"Non-organic"]) {
id sourceID = [installData objectForKey:@"media_source"];
id campaign = [installData objectForKey:@"campaign"];
NSLog(@"This is a none organic install. Media source: %@ Campaign: %@",sourceID,campaign);
} else if([status isEqualToString:@"Organic"]) {
NSLog(@"This is an organic install.");
}
}
-(void)onConversionDataFail:(NSError *) error {
NSLog(@"%@",error);
}
//Handle Direct Deep Link
- (void) onAppOpenAttribution:(NSDictionary*) attributionData {
NSLog(@"%@",attributionData);
}
- (void) onAppOpenAttributionFailure:(NSError *)error {
NSLog(@"%@",error);
}
// support for scene delegate
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13)){
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions API_AVAILABLE(ios(13.0)){
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
@end
В файле SceneDelegate.m
:
- В обратном вызове
openURLContexts
вызовитеhandleOpenUrl
. - В обратном вызове
continueUserActivity
вызовитеcontinueUserActivity
.
#import "SceneDelegate.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void) сцена: (UIScene *) сцена openURLContexts: (NSSet <UIOpenURLContext *> *) URLContexts API_AVAIL.0ABLE (ios {
NSURL * url = [[URLContexts allObjects] objectAtIndex: 0] .URL;
if (url) {
[[AppsFlyerLib shared] handleOpenUrl:url options:nil];
}
}
- (void) scene: (UIScene *) scene continueUserActivity: (NSUserActivity *) userActivity API_AVAILABLE (ios (13.0)) {
[[AppsFlyerLib shared]continueUserActivity:userActivity restorationHandler:nil];
}
- (void) scene: (UIScene *) scene willConnectToSession: (UISceneSession *) параметры сеанса: (UISceneConnectionOptions *) connectionOptions {
// Используйте этот метод для дополнительной настройки и присоединения UIWindow `window` к предоставленной UIWindowScene` scene`.
// При использовании раскадровки свойство `window` будет автоматически инициализировано и прикреплено к сцене.
// Этот делегат не подразумевает, что соединяющаяся сцена или сеанс являются новыми (вместо этого см. `Application: configurationForConnectingSceneSession`).
NSUserActivity * activity = [[connectionOptions userActivities] allObjects] .firstObject;
если (активность) {
[self scene:scene continueUserActivity:activity];
}
[собственная сцена: сцена openURLContexts: [connectionOptions URLContexts]];
}
- (void) sceneDidDisconnect: (UIScene *) scene API_AVAILABLE (ios (13.0)) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void) sceneDidBecomeActive: (UIScene *) scene API_AVAILABLE (ios (13.0)) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void) sceneWillResignActive: (UIScene *) сцена API_AVAILABLE (ios (13.0)) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void) sceneWillEnterForeground: (UIScene *) сцена API_AVAILABLE (ios (13.0)) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
- (void) sceneDidEnterBackground: (UIScene *) сцена API_AVAIL.0 (ios (ios )) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
@end
В файле AppDelegate.swift
:
- import
AppsFlyerLib
- Добавьте
AppsFlyerLibDelegate
в объявление классаAppDelegate
. - В обратном вызове
didFinishLaunchingWithOptions
укажите:- Ключ разработчика AppsFlyer
- Идентификатор приложения
- Для сбора IDFA настройте поддержку App Tracking Transparency (ATT).
- Дополнительные настройки
- Переопределите обратные вызовы
onConversionDataSuccess
иonConversionDataFail
для обработки конверсий и активации отложенного диплинкинга. - Переопределите обратные вызовы
onAppOpenAttribution
иonAppOpenAttributionFailure
для обработки атрибуции и активации прямого диплинкинга. - В обратном вызове
didReceiveRemoteNotification
вызовите методhandlePushNotification
для атрибуции повторных вовлечений, полученных при помощи push-уведомлений. - В обратном вызове
sendLaunch
вызовитеstart
.
import UIKit
import AppsFlyerLib
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, AppsFlyerLibDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
AppsFlyerLib.shared().appsFlyerDevKey = "<AF_DEV_KEY>"
AppsFlyerLib.shared().appleAppID = "<APPLE_APP_ID>"
AppsFlyerLib.shared().delegate = self
AppsFlyerLib.shared().isDebug = true
NotificationCenter.default.addObserver(self, selector: NSSelectorFromString("sendLaunch"), name: UIApplication.didBecomeActiveNotification, object: nil)
return true
}
@objc func sendLaunch() {
AppsFlyerLib.shared().start()
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
}
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
//MARK: -GCD
func onConversionDataSuccess(_ installData: [AnyHashable: Any]) {
print("onConversionDataSuccess data:")
for (key, value) in installData {
print(key, ":", value)
}
if let status = installData["af_status"] as? String {
if (status == "Non-organic") {
if let sourceID = installData["media_source"],
let campaign = installData["campaign"] {
print("This is a Non-Organic install. Media source: \(sourceID) Campaign: \(campaign)")
}
} else {
print("This is an organic install.")
}
if let is_first_launch = installData["is_first_launch"] as? Bool,
is_first_launch {
print("First Launch")
} else {
print("Not First Launch")
}
}
}
func onConversionDataFail(_ error: Error!) {
if let err = error{
print(err)
}
}
func onAppOpenAttribution(_ attributionData: [AnyHashable : Any]!) {
if let data = attributionData{
print("\(data)")
}
}
func onAppOpenAttributionFailure(_ error: Error!) {
if let err = error{
print(err)
}
}
}
В файле SceneDelegate.swift
:
- import
AppsFlyerLib
- В обратном вызове
openURLContexts
вызовитеAppsFlyerLib.shared().handleOpen
. - В обратном вызове
continue
вызовитеAppsFlyerLib.shared().continue
.
import UIKit
import AppsFlyerLib
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Обработка универсальной ссылки из убитого состояния
if let userActivity = connectionOptions.userActivities.first {
self.scene(scene, continue: userActivity)
}
// Обработка URI-схемы из убитого состояния
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
guard let _ = (scene as? UIWindowScene) else { return }
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url {
AppsFlyerLib.shared().handleOpen(url, options: nil)
}
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
3.3 Поддержка атрибуции в SKAdNetwork
Примечание
Чтобы стала доступна полная поддержка атрибуции SKAdNetwork, обновите iOS SDK до версии 6.2.3 и выше
.
SKAdNetwork — это класс, используемый iOS для проверки установки приложений рекламодателем. Для проверки установки нужны исходное приложение и рекламируемое приложение.
Исходное приложение — это приложение, которое участвует в рекламной кампании, показывая объявления, подписанные рекламной сетью. Настройка вашего приложения для отображения рекламы не входит в задачи AppsFlyer SDK. Для настройки следуйте инструкциям Apple.
Для рекламируемого приложения (приложение с AppsFlyer SDK), решение AppsFlyer SKAdNetwork использует SKAdNetwork, чтобы отправлять постбэки об атрибуции, при этом AppsFlyer собирает, переводит и агрегирует данные, поддерживая конфиденциальность пользователей. При первом запуске приложения платформа AppsFlyer сообщает SDK, как задать значение конверсии SKAdNetwork, используя настройки конфигурации, заданные маркетологом.
Чтобы использовать решение SKAdNetwork:
- Разработчику не нужно что-либо делать.
-
AppsFlyer SDK автоматически вызывает нужные SKAdNetwork API, т.е.
registerAppForAdNetworkAttribution()
иupdateConversionValue()
. Разработчику не надо их вызывать. - Не позволяйте другим SDK вызывать API SKAdNet. Это может задержать отправку постбэков iOS в AppsFlyer и изменить значение конверсий, которые мы используем для расчета метрик вовлеченности пользователей на дэшборде SKAdNetwork.
- Маркетолог должен настроить измерение SKAdNetwork в AppsFlyer.
В магазине приложений не требуется никаких действий или регистраций со стороны разработчика или маркетолога.
Чтобы отключить атрибуцию в SKAdNetwork, используйте метод API disableSKAdNetwork.
3.4 Отложить инициализацию SDK
Можно отложить инициализацию SDK и отправку данных, пока пользователь не даст согласие (например, согласие в соответствии с GDPR или COPPA).
Примечание: Это не связано с ATT, представленным в iOS 14.
Чтобы отложить инициализацию SDK:
- Запретите отправку сеанса при переходе из фонового режима в активный. В методе sendLaunch() (который вызывается при каждом applicationDidBecomeActive (как описано в разделе 3.3), оберните вызов
start
с проверкой состояния. Например:
-(void)sendLaunch:(UIApplication *)application { if (consent_given) { // check the condition [[AppsFlyerLib shared] start]; // Start } }
-
Отправьте сеанс, как только исчезнет причина задержки (сразу после изменения состояния). Вызовите
start
, когда вы будете готовы отправить данные первого сеанса. Например:
... consent_given = YES; // change the condition [[AppsFlyerLib shared] start]; // Start ...
4. Протестируйте инсталлы
Теперь можно начинать тестирование интеграции SDK, имитируя органические и неорганические установки.
Дополнительные сценарии тестирования и инструкции см. в разделе Тестирование интеграции SDK.
Примечание
Когда вы закончите тестирование и отладку интеграции SDK, отключите журналы SDK.
4.1 Регистрация тестового устройства
Перед тем, как начать тестирование установок:
- Убедитесь, что на вашем устройстве не установлено приложение.
- Зарегистрируйте устройство, на котором вы планируете проводить тестирование.
4.2. Моделирование органической установки
Органические установки — это неатрибутированные установки, которые обычно выполняются непосредственно из магазинов приложений.
Для имитации органической установки выполните следующие действия:
- Убедитесь, что к вашему компьютеру подключено мобильное устройство.
- Откройте терминал отладки в Xcode.
- Используя Xcode Studio, установите приложение на устройство или симулятор.
- Дождитесь запуска приложения.
- Найдите в терминале отладки имя пакета своего приложения.
Вы увидите на экране такие строки:
Send start() в журнале указывает на то, что SDK сообщил об установке. Данные были получены из метода onConversionDataSuccess
в делегате приложения. Способ получения данных о конверсиях описан далее в этой руководстве.
Примечание: Начиная с SDK V5, имя метода для получения данных о конверсиях — onConversionDataSuccess
. Если вы используете версию SDK ниже 5.0.0, имя метода onConversionDataReceived
. Мы рекомендуем обновить SDK до версии 5.0.0. Подробнее см. тут.
После этого сведения об органической установке должны появиться на обзорном дэшборде приложения.
Если на дэшборде приложения нет сведений об установке, см. наше руководство по поиску и устранению неисправностей в SDK.
4.3. Моделирование неорганической установки
Неорганическая установка — это атрибутированная установка, которая обычно происходит после взаимодействия с рекламой. Для имитации неорганической установки можно использовать ссылки атрибуции.
Порядок действий:
- Найдите имя вашего приложения в itunes, например id123456789.
- В ссылке ниже замените <APP_ID> на itunes-идентификатор вашего приложения:
Например:https://app.appsflyer.com/<APP_ID>?pid=sdk_test&c=sdk_test
Параметрhttps://app.appsflyer.com/id0123456789?pid=sdk_test&c=sdk_test
pid
— это название медиаисточника. Параметрc
— это название кампании. - Отправьте этот URL на устройство (например, по электронной почте или WhatsApp).
- На устройстве нажмите на этот URL-адрес.
- Если приложение зарегистрировано в магазине приложений, произойдет перенаправление в магазин приложений. Не скачивайте приложение из магазина приложений. Перейдите к пункту 5.
- Если приложение все еще в разработке и не зарегистрировано в магазине приложений, на экране появится сообщение о том, что этого приложения в магазине приложений нет. Просто перейдите к пункту 5.
- Откройте терминал отладки в Xcode studio.
- Подключите устройство к компьютеру с помощью USB-кабеля.
- Установите приложение на устройство из Xcode Studio.
- Найдите в терминале отладки itunes идентификатор своего приложения.
Вы увидите на экране такие строки:
После этого сведения о неорганической установке должны появиться на обзорном дэшборде приложения.
Эта вкладка содержит описание способов регистрации внутренних событий приложения и данных о доходах, а также процедуры настройки диплинкинга.
Регистрация in-app событий приложения и данных о доходах позволит вам измерять качество ваших пользователей. Диплинкинг позволяет обеспечить пользователям более простой и удобный UX с рекламой и приложением.
Эта вкладка содержит инструкции для разработчиков, однако участие маркетологов также необходимо по таким причинам:
- Маркетолог решает, какие события в приложении нужно регистрировать, чтобы измерять качество пользователей.
- Маркетолог имеет доступ к панели управления AppsFlyer, которая используется для настройки ссылки OneLink для диплинкинга.
5. Регистрируйте внутренние события приложения
Отслеживая события внутри приложения, можно понять, что в нем происходит. Рекомендуется заранее определить, какие события нужно регистрировать. Регистрация внутренних событий приложения позволит измерять такие KPI, как ROI (окупаемость инвестиций) и LTV (жизненный цикл клиента).
Есть несколько способов регистрации внутренних событий приложения. Наиболее распространенный способ — это отправка событий через SDK. Именно этот способ и рассматривается в этой статье. Сведения о других способах регистрации событий в приложении см. в нашем обзоре внутренних событий приложения.
Если ваше приложение относится к определенной сфере, например к сфере путешествий, игр, электронной коммерции и т. д., вы можете ознакомиться с полным списком рекомендованных событий для каждой сферы.
5.1. Имена внутренних событий в приложении и параметры
SDK содержит два типа констант, которые представляют информацию, связанную с событиями в приложении.
- Названия событий: эти константы имеют формат
AFEventEventName
.
Например,AFEventPurchase
,AFEventAddToCart
. - Параметры событий - Эти константы имеют формат
AFEventParameterParameterName
.
Например,AFEventParameterRevenue
,AFEventParamaterContentId
.
Мы настоятельно рекомендуем использовать эти константы по следующим причинам:
- Стандартное именование позволяет AppsFlyer автоматически сопоставлять события с сетями типа SRN, такими как Facebook, Google, Twitter и Snapchat.
- Обратная совместимость — если AppsFlyer решит изменить имя какого-либо события или параметра события, ваши настройки останутся совместимыми.
Чтобы использовать эти два интерфейса, нужно импортировать AppsFlyerLib.h, если вы используете Objective-C, или AppsFlyerLib, если вы используете Swift:
Поместите это в файл применения класса.
#import AppsFlyerLib.h
Поместите это в файл класса Swift.
import AppsFlyerLib
5.2 Регистрация дохода
Данные о доходах можно отправлять с любым внутренним событием приложения. Используйте параметр сообщения af_revenue
(AFEventParameterRevenue
), чтобы включить доход во внутреннее событие приложения. Этому параметру можно присвоить любое числовое значение — как положительное, так и отрицательное.
af_revenue
— это единственный параметр события, который AppsFlyer учитывает как реальный доход и отображает в отчетах сырых данных и на панели управления. Подробные сведения см. здесь.
При отправке событий с доходом необходимо учитывать следующее:
- При установке кода местной валюты (см. пример ниже) необходимо использовать код валюты из 3 букв по стандарту ISO 4217 (значение по умолчанию — USD).
- Вы можете настроить код валюты для всех событий, установив следующее свойство:
- Objective-C:
[AppsFlyerLib shared].currencyCode = @"ZZZ";
, - Swift:
AppsFlyerLib.shared().currencyCode = "ZZZ"
- Objective-C:
- В значениях дохода нельзя использовать запятые-разделители, знаки валюты или текст. Событие дохода должно иметь, например, такой формат: 1234.56.
Пример: событие покупки в приложении с доходом
[[AppsFlyerLib shared] logEvent: @"purchase"
withValues:@{
AFEventParamContentId:@"1234567",
AFEventParamContentType : @"category_a",
AFEventParamRevenue: @200,
AFEventParamCurrency:@"USD"
}];
AppsFlyerLib.shared().logEvent("purchase",
withValues: [
AFEventParamContentId:"1234567",
AFEventParamContentType : "category_a",
AFEventParamRevenue: 200,
AFEventParamCurrency:"USD"
]);
В этом событии покупки указан доход $200, который будет отображаться на панели управления.
Регистрация отрицательного дохода
Возможны ситуации, в которых нужно зарегистрировать отрицательный доход.
Пример: пользователь приложения получает возмещение или отменяет подписку.
[[AppsFlyerLib shared] logEvent: @"cancel_purchase"
withValues:@{
AFEventParamContentId:@"1234567",
AFEventParamContentType : @"category_a",
AFEventParamRevenue: @-1.99,
AFEventParamCurrency:@"USD"
}];
AppsFlyerLib.shared().logEvent("cancel_purchase",
withValues: [
AFEventParamContentId:"1234567",
AFEventParamContentType : "category_a",
AFEventParamRevenue: -1.99,
AFEventParamCurrency:"USD"
]);
Примечание
Обратите внимание на приведенный выше код:
- Перед значением дохода стоит знак минус
- Имя события имеет уникальное значение "cancel_purchase", которое позволяет легко найти события отрицательного дохода на панели управления и в отчетах сырых данных.
5.3. Проверка покупок в приложении
При покупках в приложении SDK AppsFlyer выполняет проверку на сервере. Чтобы проверить покупку, вызовите метод validateAndLogInAppPurchase
.
Если покупка проверена, этот запрос автоматически создает внутреннее событие приложения af_purchase
.
Этот вызов содержит два блока обратного вызова — один для сценария «успешно», а второй для сценария «ошибочно» (по любой причине, включая сбой валидации). В случае сценария «успешно» словарь получит в ответ подтверждение контрольных данных, предоставляемых серверами Apple.
Пример применения проверки покупки
- (void) validateAndLogInAppPurchase:(NSString *) productIdentifier
price:(NSString *) price
currency:(NSString *) currency
transactionId:(NSString *) tranactionId
additionalParameters:(NSDictionary *) params
success:(void (^)(NSDictionary *response)) successBlock
failure:(void (^)(NSError *error, id reponse)) failedBlock;
[[AppsFlyerLib shared] validateAndLogInAppPurchase:@"ProductIdentifier" price:@"price"
currency:@"USD"
transactionId:@"transactionID"
additionalParameters:@{@"test": @"val" , @"test1" : @"val 1"}
success:^(NSDictionary *result){
NSLog(@"Purchase succeeded And verified!!! response: %@", result[@"receipt"]);
} failure:^(NSError *error, id response) {
NSLog(@"response = %@", response);
if([response isKindOfClass:[NSDictionary class]]) {
if([response[@"status"] isEqualToString:@"in_app_arr_empty"]){
// retry with 'SKReceiptRefreshRequest' because
// Apple has returned an empty response
// <YOUR CODE HERE>
}
} else {
//handle other errors
return;
}
}];
AppsFlyerLib
.shared()?
.validateAndLogInAppPurchase ("productIdentifier",
price: "price",
currency: "currency",
transactionId: "transactionId",
additionalParameters: [:],
success: {
guard let dictionary = $0 as? [String:Any] else { return }
dump(dictionary)
}, failure: { error, result in
guard let emptyInApp = result as? [String:Any],
let status = emptyInApp["status"] as? String,
status == "in_app_arr_empty" else {
// Try to handle other errors
return
}
// retry with 'SKReceiptRefreshRequest' because
// Apple has returned an empty response
// <YOUR CODE HERE>
})
При тестировании проверки покупки в безопасной среде добавьте следующий код:
[AppsFlyerLib shared].useReceiptValidationSandbox = YES;
AppsFlyerLib.shared().useReceiptValidationSandbox = true
Обратите внимание, что этот код необходимо удалить из ваших рабочих сборок.
Валидация покупки в приложении автоматически отправляет в AppsFlyer данные события о покупке. Далее приведены примеры данных, которые передаются в параметре event_value:
{
"some_parameter":"some_value", // from additional_event_values
"af_currency":"USD", // from currency
"af_content_id":"test_id", // from purchase
"af_revenue":"10", // from revenue
"af_quantity":"1", // from purchase
"af_validated":true // flag that AF verified the purchase
}
Примечание
Вызов validateAndTrackInAppPurchase
автоматически создает внутри приложения событие af_purchase. При самостоятельной отправке этого события происходит дублирование данных о событии.
5.4. Ограничения для внутренних событий приложения
- Название события: до 45 символов
- Значение события: не более 1000 символов, более длинные сообщения могут быть урезаны
- В значениях цены и дохода можно использовать только цифры и десятичную точку, например 5 или 5.2.
- Значения цены и дохода могут иметь не более 5 знаков после десятичной точки, например 5.12345
- Неанглийские символы поддерживаются во внутренних события приложения и других SDK API, начиная с SDK для Android версии 4.8.1.
5.5. Примеры регистрации внутренних событий приложения
Для регистрации внутренних событий приложения используется вызов функции trackRichEvent
с именем события и значениями параметров. Подробные сведения см. в статье о in-app событиях.
Ниже приведен простой пример способа регистрации события покупки. Полный список готовых фрагментов кода для различных отраслей см. в нашем руководстве по насыщенным внутренним событиям приложения применительно к отраслям.
Пример: событие покупки в приложении
[[AppsFlyerLib shared] logEvent:AFEventPurchase
withValues: @{
AFEventParamRevenue: @200,
AFEventParamCurrency: @"USD",
AFEventParamQuantity: @2,
AFEventParamContentId: @"092",
AFEventParamReceiptId: @"9277"
}];
Примечание
- Словарь значения события, передаваемый в SDK события, должен быть действительным для преобразования JSON посредством NSJSONSerialization. Подробные сведения см. здесь.
- Не добавляйте к значению выручки символы денежных единиц, поскольку они не распознаются.
AppsFlyerLib.shared().logEvent(AFEventPurchase,
withValues: [
AFEventParamRevenue: "200",
AFEventParamCurrency: "USD",
AFEventParamQuantity: 2,
AFEventParamContent: "shoes",
AFEventParamContentId: "092",
AFEventParamReceiptId: "9277"]);
5.6 Регистрация внутренних событий приложения в режиме оффлайн
Если пользователь инициирует событие, когда подключение к Интернету недоступно, Appsflyer все же сможет записать это событие. Вот как это работает:
- SDK отправляет события на серверы AppsFlyer и ждет ответа.
- Если SDK не получит ответа «200», событие будет помещено в кэш.
- Если затем будет получен ответ «200», сохраненное событие отправляется на сервер повторно.
- Если в кэше хранится несколько событий, они отправляются на сервер одно за другим без перерывов.
Примечание
В кэше SDK можно хранить не более 40 событий. Это означает, что сохраняются только первые 40 событий, происходящих в автономном режиме. Все, что приходит после этого до следующего ответа «200», игнорируется.
Время события, которое появляется в необработанных данных — это время события, которое отправляется в AppsFlyer после того, как устройство снова выходит в сеть. Это время не равнозначно времени, когда событие происходит.
5.7 Обработка успешных и неудачных попыток при регистрации внутренних событий приложения
- Внутреннее событие приложения зарегистрировано успешно.
- При регистрации внутреннего события произошла ошибка.
[[AppsFlyerLib shared] logEventWithEventName:AFEventPurchase
eventValues: @{
AFEventParamRevenue: @200,
AFEventParamCurrency: @"USD",
AFEventParamQuantity: @2,
AFEventParamContentId: @"092",
AFEventParamReceiptId: @"9277"
}
completionHandler:^(NSDictionary<NSString *,id> * _Nullable dictionary, NSError * _Nullable error){
if(dictionary != nil) {
NSLog(@"In app callback success:");
for(id key in dictionary){
NSLog(@"Callback response: key=%@ value=%@", key, [dictionary objectForKey:key]);
}
}
if(error != nil) {
NSLog(@"In app callback error:", error);
}
}];
AppsFlyerLib.shared().logEvent(name: "In app event name", values: ["id": 12345, "name": "John doe"], completionHandler: { (response: [String : Any]?, error: Error?) in
if let response = response {
print("In app event callback Success: ", response)
}
if let error = error {
print("In app event callback ERROR:", error)
}
})
}
В случае возникновения ошибки во время записи внутреннего события отображается код ошибки и описание строки, как указано в таблице ниже.
Код ошибки | Описание строки |
---|---|
10 |
"Event timeout." (Таймаут события) Check 'minTimeBetweenSessions' param" ("Время события истекло. Проверьте параметр 'minTimeBetweenSessions'") |
11 |
"Skipping event because 'isStopTracking' enabled" (Событие пропущено, т.к. включен параметр 'isStopTracking'") |
40 |
Ошибка сети: описание ошибки предоставляет Android |
41 |
"No dev key" ("Нет ключа разработчика") |
50 |
"Status code failure" ("Ошибка кода статуса") + фактический код ответа от сервера |
6. Диплинкинг при помощи OneLink
OneLink — это решение AppsFlyer для многоплатформенной атрибуции, перенаправления и диплинкинга.
6.1. Идентификация устройств и перенаправление пользователей
При нажатии на ссылку OneLink определяется тип устройства и пользователь перенаправляется в соответствующий пункт назначения, например на портал Google Play, в магазин приложений для iOS, на независимую торговую площадку или веб-страницу.
В руководстве по настройке OneLink рассматривается атрибуция с использованием многоплатформенных ссылок (программирование SDK не требуется). Эти ссылки можно также использовать для диплинкинга.
6.2. Диплинкинг
Диплинкинг позволяет направлять пользователей на определенное действие в приложении, предоставляя им индивидуально подобранный контент. Такие возможности очень полезны при проведении ретаргетинговых кампаний.
Настройку диплинкинга при помощи Onelink должны совместно выполнять маркетолог с доступом к панели управления AppsFlyer и разработчик с доступом к приложению.
См. наше руководство по настройке диплинкинга при помощи OneLink.
6.3. Отложенный диплинкинг
Отложенный диплинкинг позволяет перенаправлять новых пользователей по глубинной ссылке и предоставлять им после первого запуска приложения индивидуально подобранный контент. Этот метод отличается от обычного диплинкинга, который можно использовать, только если приложение уже установлено на устройстве пользователя.
Чтобы настроить отложенный диплинкинг при помощи OneLink, разработчику также необходим доступ к панели управления AppsFlyer.
Настройка отложенного диплинкинга выполняется так же, как и настройка обычного диплинкинга. Единственное отличие состоит в том, что для перенаправления пользователей по глубинной ссылке и предоставления им индивидуально подобранного контента после установки и запуска приложения необходимо добавить в приложение соответствующий код.
Дополнительные сведения см. в руководстве по отложенному диплинкингу.
6.4 Доступ к данным диплинков
SDK предоставляет данные о конверсии или вовлечении после каждого события установки или перехода по глубинной ссылке. Эти данные можно использовать для программной настройки контента и поведения приложения.
Чтобы получать данные по диплинкингу, когда используется прямой диплинк и открыто приложение, внедрите метод onAppOpenAttribution.
Чтобы получать данные по диплинкингу для повторного вовлечения вручную в любое время, внедрите метод performOnAppAttribution. Это позволяет получить доступ к данным по повторному вовлечению, не регистрируя новое повторное вовлечение.
Дополнительные сведения см. в руководстве по настройке диплинкинга.
6.5 Настройка разрешения диплинков в push-уведомлениях
Владельцы приложений могут использовать метод addPushNotificationDeepLinkPath
как гибкий интерфейс для настройки способа извлечения диплинков из полезной нагрузки push-уведомлений.
По умолчанию SDK ищет значение диплинка в ключе af
из полезной нагрузки JSON
push-уведомления. Многие поставщики push-уведомлений используют собственные схемы JSON
, которые SDK не может расшифровать без дополнительной настройки.
С помощью addPushNotificationDeepLinkPath
можно определить, в каком ключе в полезной нагрузке push-уведомления SDK будет искать значение диплинка.
Используйте этот метод, если вы интегрируете приложение с поставщиками push-уведомлений, которые не используют стандартную схему JSON для push-уведомлений, ожидаемую SDK.
При вызове addPushNotificationDeepLinkPath
SDK проверяет, что:
- В полезной нагрузке присутствует необходимый ключ.
- Ключ содержит действительный URL OneLink.
Базовая конфигурация
Проанализируйте следующий вызов addPushNotificationDeepLinkPath
[AppsFlyerLib shared] addPushNotificationDeepLinkPath:@[@"deeply", @"nested", @"deep_link"]]
AppsFlyerLib.shared().addPushNotificationDeepLinkPath(["deeply", "nested", "deep_link"])
и эти сценарии:
Сценарий 1
Приложение вызывается с помощью push-уведомления, которое содержит полезную нагрузку со следующей структурой.
{
...
"deeply": {
"nested": {
"deep_link": "https://yourdeeplink2.onelink.me"
}
}
...
}
В этом сценарии SDK извлекает значение deep_link
и продолжает выполнять диплинкинг.
Сценарий 2
Приложение вызывается с помощью push-уведомления, которое содержит полезную нагрузку со следующей структурой.
{
...
"deeply": {
"nested": {
"banana": "https://yourdeeplink2.onelink.me"
}
},
...
}
В этом сценарии при исполнении вызова SDK не находит ключ deep_link
в полезной нагрузке. Поэтому ничего не происходит.
Сценарий 3
Приложение вызывается с помощью push-уведомления, которое содержит полезную нагрузку со следующей структурой.
{
...
"deeply": {
"nested": {
"deep_link": "Corrupted url or regular string"
}
},
...
}
В этом сценарии SDK находит ключ deep_link
, но указанное в нем значение диплинка недействительно. Поэтому при выполнении вышеуказанного вызова ничего не происходит.
Расширенные настройки
Чтобы настроить несколько возможных структур полезной нагрузки метод addPushNotificationDeepLinkPath
вызывается несколько раз:
- Использоваться будет тот вызов, который первым вернет действительное значение диплинка.
- Другие вызовы игнорируются
Если ни одна из структур полезной нагрузки не подходит, или в полезной нагрузке не найден действительный URL-адрес OneLink, ничего не происходит.
Например, рассмотрим полезную нагрузку
{
...
"deeply": {
"nested": {
“deep_link”: “https://yourdeeplink2.onelink.me”
}
},
“this”: {
“is”: {
"banana": "phone"
}
}
...
}
и следующие вызовы метода addPushNotificationDeepLinkPath
.
// this.is.deep_link key isn’t found - nothing happens
[AppsFlyerLib shared] addPushNotificationDeepLinkPath:@[@"this", @"is", @"deep_link"]]
// this.is.banana key found, but contains invalid OneLink URL - nothing happens
[AppsFlyerLib shared] addPushNotificationDeepLinkPath:@[@"this", @"is", @"banana"]]
// deeply.nested.deep_link key found and contains valid OneLink URL - proceed deep linking flow
[AppsFlyerLib shared] addPushNotificationDeepLinkPath:@[@"deeply", @"nested", @"deep_link"]]
// this.is.deep_link key isn’t found - nothing happens
AppsFlyerLib.shared().addPushNotificationDeepLinkPath(["this", "is", "deep_link"]);
// this.is.banana key found, but contains invalid OneLink URL - nothing happens
AppsFlyerLib.shared().addPushNotificationDeepLinkPath(["this", "is", "banana"])
// deeply.nested.deep_link key found and contains valid OneLink URL - proceed deep linking flow
AppsFlyerLib.shared().addPushNotificationDeepLinkPath(["deeply", "nested", "deep_link"])
7. Получение данных о конверсиях
Получите данные о конверсиях
Вы получаете доступ к данным атрибуции пользователей для каждой новой установки в реальном времени непосредственно на уровне SDK.
Таким образом, можно предоставлять пользователям персонализированный контент или направлять их на определенные действия в приложении (см. раздел Отложенный диплинкинг в этой статье), что позволит значительно улучшить их взаимодействие с вашим приложением.
Чтобы получить данные о конверсии из iOS SDK, используйте следующие методы:
- (void) onAppOpenAttribution:(NSDictionary*) attributionData {
NSLog(@"onAppOpenAttribution");
for(id key in attributionData){
NSLog(@"onAppOpenAttribution: key=%@ value=%@", key, [attributionData objectForKey:key]);
}
}
- (void)onAppOpenAttributionFailure:(NSError *)error {
NSLog(@"%@", [error description]);
}
-(void)onConversionDataSuccess:(NSDictionary*) installData {
BOOL first_launch_flag = [[installData objectForKey:@"is_first_launch"] boolValue];
NSString *status = [installData objectForKey:@"af_status"];
if(first_launch_flag) {
if ([status isEqualToString:@"Non-organic"]){
NSString *sourceID = [installData objectForKey:@"media_source"];
NSString *campaign = [installData objectForKey:@"campaign"];
NSLog(@"This is a non-organic install. Media source: %@ Campaign: %@", sourceID, campaign);
} else {
NSLog(@"This is an organic install");
}
} else {
NSLog(@"Not first launch");
}
}
-(void)onConversionDataFail:(NSError *) error {
NSLog(@"%@", [error description]);
}
class AppDelegate: UIResponder, UIApplicationDelegate, AppsFlyerLibDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
AppsFlyerLib.shared().appsFlyerDevKey = "MY_DEV_KEY"
AppsFlyerLib.shared().appleAppID = "123456789"
AppsFlyerLib.shared().delegate = self
//AppsFlyerLib.shared().isDebug = true
//AppsFlyerLib.shared().appInviteOneLinkID = "ONELINK_ID";
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
AppsFlyerLib.shared().start()
}
func onConversionDataSuccess(_ installData: [AnyHashable: Any]) {
guard let first_launch_flag = installData["is_first_launch"] as? Int else {
return
}
guard let status = installData["af_status"] as? String else {
return
}
if(first_launch_flag == 1) {
if(status == "Non-organic") {
if let media_source = installData["media_source"] , let campaign = installData["campaign"]{
print("This is a Non-Organic install. Media source: \(media_source) Campaign: \(campaign)")
}
} else {
print("This is an organic install.")
}
} else {
print("Not First Launch")
}
}
func onConversionDataFail(_ error: Error!) {
if let err = error{
print(err)
}
}
func onAppOpenAttribution(_ attributionData: [AnyHashable : Any]!) {
if let data = attributionData{
print("\(data)")
}
}
func onAppOpenAttributionFailure(_ error: Error!) {
if let err = error{
print(err)
}
}
Два наиболее важных метода:
-
onConversionDataSuccess
— предоставляет данные о конверсии для новых установок.
Примечание: Начиная с SDK V5, имя метода для получения данных о конверсиях —
onConversionDataSuccess
. Если вы используете версию SDK ниже 5.0.0, имя методаonConversionDataReceived
. Мы рекомендуем обновить SDK до версии 5.0.0. Подробнее см. тут. -
onAppOpenAttribution
— предоставляет данные о конверсиях ретаргетинга при запуске существующего приложения вручную либо с помощью глубинной ссылки.
Дополнительные сведения относительно данных о конверсиях см. в нашем руководстве по сценариям использования данных о конверсиях.
8. Атрибуция
Измерение количества удалений приложений
Инструкции по настройке измерения количества удалений см. здесь.
Настройка запуска SDK
Если вы хотите получить подтверждение, что SDK запущен успешно и уведомил серверы AppsFlyer, используйте обработчик startWithCompletionHandler
. Затем результат применения этого метода (SDK запущен / не запущен) можно обработать с помощью логических операторов.
Пример использования
[[AppsFlyerLib shared] startWithCompletionHandler:^(NSDictionary<NSString *,id> *dictionary, NSError *error) {
if (error) {
NSLog(@"%@", error);
return;
}
if (dictionary) {
NSLog(@"%@", dictionary);
return;
}
}];
AppsFlyerLib.shared()?.start(completionHandler: { (dictionnary, error) in
if (error != nil){
print(error ?? "")
return
} else {
print(dictionnary ?? "")
return
}
})
В случае возникновения ошибки во время работы прослушивателя запросов отображается код ошибки и описание строки, как указано в таблице ниже.
Код ошибки | Описание строки |
---|---|
10 |
"Event timeout." (Таймаут события) Check 'minTimeBetweenSessions' param" ("Время события истекло. Проверьте параметр 'minTimeBetweenSessions'") |
11 |
"Skipping event because 'isStopTracking' enabled" (Событие пропущено, т.к. включен параметр 'isStopTracking'") |
40 |
Ошибка сети: описание ошибки предоставляет Android |
41 |
"No dev key" ("Нет ключа разработчика") |
50 |
"Status code failure" ("Ошибка кода статуса") + фактический код ответа от сервера |
Настройка дополнительных пользовательских данных
API setAdditionalData
необходим для интеграции на уровне SDK с несколькими внешними партнерским платформами, включая Segment, Adobe и Urban Airship.
Используйте данный API только в тех случаях, когда в руководстве по интеграции платформы специально указана необходимость использования API setAdditionalData
.
Пример кода setAdditionalData
:
NSDictionary* customDataMap = [[NSDictionary alloc] initWithObjectsAndKeys:@"value_of_param_1", @"custom_param_1", nil];
[[AppsFlyerLib shared] setAdditionalData:customDataMap];
let customDataMap: [AnyHashable: Any] = [
"custom_param_1" : "value_of_param_1"
]
AppsFlyerLib.shared().customData = customDataMap
Атрибуция сессий приложения, инициированных с собственных сайтов (доменов)
Владельцы приложений, использующие универсальные ссылки для диплинкинга (без OneLink) и имеющие домен, связанный с их приложением, могут атрибутировать сессии, инициированные через этот домен, с помощью метода appendParametersToDeepLinkingURL
.
Например, пользователь ищет что-то в Google и кликает по ссылке на ваш домен www.example.com:
- Если у пользователя не установлено приложение, он направляется на веб-сайт (www.example.com).
- Если приложение уже установлено на устройстве этого пользователя, диплинк приведет его в приложение, связанное с доменом www.example.com. Данная сессия атрибутируется медиа-источнику (параметр
pid
), указанному вappendParametersToDeepLinkingURL
.
Дополнительную информацию см. в материалах по iOS SDK.
Заметьте: Смарт-баннеры помогают конвертировать посетителей сайта в пользователей мобильного приложения.
9. Сеансы
Настройка временного интервала между сеансами
По умолчанию два сеанса учитываются как отдельные, если интервал между двумя запусками приложения составляет не меньше 5 секунд (см. дополнительные сведения об учете сеансов).
Чтобы установить минимальный интервал между сеансами, используйте этот API:
[AppsFlyerLib shared].minTimeBetweenSessions = <your_custom_time_in_seconds>;
AppsFlyerLib.shared().minTimeBetweenSessions = <your_custom_time_in_seconds>
Установка большого интервала между запусками может отрицательно сказаться на работе API, которые используют данные сеансов, например, для диплинкинга.
Фоновые сеансы для служебных приложений
Недоступно в iOS.
10. Собственные медиаканалы
Разрешение упакованных URL-адресов глубинных ссылок
Некоторые сторонние службы, такие как службы электронной почты упаковывают ссылки в электронных письмах в свои собственные домены регистрации кликов. Некоторые даже разрешают вам устанавливать свои собственные домены регистрации кликов. Упаковка ссылки OneLink в такие домены может привести к ограничению ее функциональных возможностей.
Чтобы преодолеть эту проблему, можно использовать API setResolveDeepLinkURLs
. Этот API позволяет получать ссылки OneLink от доменов кликов, которые запускают приложение. Этот API нужно обязательно вызвать перед инициализацией SDK.
Например, у вас есть три домена регистрации кликов, которые выполняют перенаправление на вашу ссылку OneLink по адресу https://mysubdomain.onelink.me/abCD. Используйте этот API для получения ссылки OneLink, на которую перенаправляют домены регистрации кликов. Этот метод API получает список доменов, разрешение которых выполняет SDK.
[AppsFlyerLib shared].resolveDeepLinkURLs = @[@"example.com",@"click.example.com"];
AppsFlyerLib.shared().resolveDeepLinkURLs = ["example.com", "click.example.com"]
Приведенный выше код позволяет использовать домен регистрации кликов, сохраняя при этом функциональные возможности OneLink. Домены регистрации кликов выполняют запуск приложения. API, в свою очередь, получает от этих доменов ссылку OneLink, после чего данные этой ссылки OneLink можно использовать для диплинкинга и персонализации пользовательского контента.
Регистрация push-уведомлений
С помощью AppsFlyer можно выполнять измерения push-уведомлений при проведении кампаний по ретаргетингу.
Чтобы включить эту функцию, вызовите метод handlePushNotificationData
внутри AppDelegate.m.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[[AppsFlyerLib shared] handlePushNotification:userInfo];
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
AppsFlyerLib.shared().handlePushNotification(userInfo)
}
Подробные сведения об измерении push-уведомлений см. здесь.
Атрибуция приглашений пользователей
С их помощью уже имеющиеся пользователи могут приглашать своих друзей и знакомых в качестве новых пользователей вашего приложения, что может существенно способствовать его продвижению. С помощью AppsFlyer можно атрибутировать и регистрировать установки, источником которых являются приглашения, отправленные пользователями из вашего приложения.
Подробные сведения см. в статье Атрибуция приглашений пользователей.
Атрибуция в кампаниях перекрестной рекламы
Внимание! Для перекрестной рекламы по IDFV требуется SDK 6.0.2 или новее. Идентификаторы IDFV собираются автоматически, от разработчика не требуется дополнительных действий.
Перекрестная реклама позволяет значительно увеличить количество установок ваших приложений. AppsFlyer позволяет атрибутировать и регистрировать установки, источником которых является перекрестная реклама одного из ваших приложений в другом приложении, которое уже есть у пользователя.Подробные сведения см. в статье Атрибуция в кампаниях перекрестной рекламы.
11. Идентификаторы пользователей
Получение AppsFlyer ID
Для каждой новой установки приложения AppsFlyer создает уникальный ID. Вы можете использовать этот ID для различных целей:
- Отправляйте внутренние события приложения от сервера к серверу.
- Сопоставьте его с данными пользователей в ваших back-end системах.
- Сопоставляйте записи при объединении данных из Pull API и Push API.
Для получения уникального ID используйте следующий API:
NSString *appsflyerId = [AppsFlyerLib shared].getAppsFlyerUID;
let appsflyerId = AppsFlyerLib.shared().getAppsFlyerUID()
Установка Customer User ID
Для установки собственного Customer User ID используйте такой код:
[AppsFlyerLib shared].customerUserID = @"my user id";
AppsFlyerLib.shared().customerUserID = "my user id"
В iOS идентификатор пользователя необходимо устанавливать с каждым запуском приложения. Рекомендуется установить свой ID клиента на раннем этапе продвижения приложения, так как после установки этого идентификатора только он привязывается к событиям, включаемым в отчеты:
- Если вызов
setCustomerUserId
выполняется перед вызовомstart
, идентификатор клиента будет отображаться в отчетах по сырым данным и для установок, и для событий. - Если установить ID клиента позже, он будет привязан только к событиям, зарегистрированным после установки этого идентификатора.
Получение Customer User ID:
Чтобы избежать необходимости повторно устанавливать значение ID клиента после первого запуска и многократно обращаться к серверу для его получения, проверьте, задано ли его значение, с помощью этого кода:
NSString *customerUserID = [AppsFlyerLib shared].customerUserID;
let customerUserID = AppsFlyerLib.shared().customerUserID
Для получения дополнительных сведений о Customer User ID щелкните здесь.
Задержка инициализации SDK для идентификатора customerUserID
Можно отложить инициализацию SDK до настройки идентификатора customerUserID. Это полезно, если вы хотите, чтобы в ваших данных об установках и событиях содержался идентификатор пользователя.
Добавьте следующий код:
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSString *customUserId = [[NSUserDefaults standardUserDefaults] stringForKey:@"customerUserId"]; // Your custom logic of retrieving CUID
if (customUserId != nil && ![customUserId isEqual: @""]) {
[AppsFlyerLib shared].customerUserID = customUserId; // Set CUID in AppsFlyer SDK for this session
[[AppsFlyerLib shared] start]; // Start
}
}
func applicationDidBecomeActive(_ application: UIApplication) {
let customUserId = UserDefaults.standard.string(forKey: "customUserId") // your logic to retrieve CUID
if(customUserId != nil && customUserId != ""){
AppsFlyerLib.shared().customerUserID = customUserId // Set CUID in AppsFlyer SDK for this session
AppsFlyerLib.shared().start() // Start
}
}
Дополнительные сведения об отсрочке инициализации SDK до получения идентификатора клиента см. здесь.
Предупреждение
Используйте данный API, только если он соответствует логике функционирования приложения. Использование данного API повышает вероятность расхождений и уязвимость приложения для мошенничества.
12. Защита конфиденциальной информации пользователей
Отказ от использования данных
В исключительных случаях может потребоваться полное отключение средств SDK для соблюдения норм законодательства и правил конфиденциальности. Это может быть реализовано с помощью параметра isStopped. Когда для параметра установлено значение true, SDK прекратит работу и обмен данных с серверами AppsFlyer.
Есть несколько различных сценариев, которые владелец приложения может применить для прекращения отслеживания пользователя. Настоятельно рекомендуется строго следовать инструкциям сценария, применимого для вашего приложения.
Предупреждение
Используйте API isStopped только в тех случаях, когда необходимо полностью исключить данного пользователя из всех процессов регистрации. Использование этого API СУЩЕСТВЕННО влияет на атрибуцию, сбор данных и механизм диплинкинга.
[AppsFlyerLib shared].isStopped = true;
AppsFlyerLib.shared().isStopped = true
В любом случае SDK можно активировать повторно путем вызова того же API с передачей значения "false".
Важно!
Не вызывайте start
, если параметр isStopped
установлен на значение true
.
Чтобы возобновить предоставление данных, установите isStopped
на значение false
.
Анонимизация пользовательских данных
Для реализации явной анонимизации установок, событий и сеансов пользователя используйте этот API во время инициализации SDK:
[AppsFlyer shared].disableAdvertisingIdentifier = YES;
AppsFlyerLib.shared().disableAdvertisingIdentifier = true
Предоставление данных можно запустить снова, установив anonymizeUser
на значение false.
Предупреждение
Анонимизация пользователей влияет на данные атрибуции.Используйте этот параметр только в тех случаях, когда сбор информации о пользователях запрещен законодательно.
Настройка поддержки фреймворка App Tracking Transparency (ATT)
По сообщениям Apple, начиная с iOS 14.5 для сбора IDFA будет требоваться разрешение пользователя. Фактически это означает, что доступом к IDFA будет управлять фреймворк App Tracking Transparency (ATT). На устройствах с iOS 14 и выше для получения доступа к IDFA устройства SDK AppsFlyer для iOS использует фреймворк ATT.
Если атрибуция выполняется с использованием IDFA, важно, чтобы IDFA отправлялся при первом запуске. Для этого в SDK предусмотрена утилита waitForATTUserAuthorization
.
Обзор реализации
waitForATTUserAuthorization
позволяет настроить, на сколько SDK будет задерживать отправку данных на серверы AppsFlyer, ожидая получения статуса ATT. Для полной реализации поддержки ATT:
- Настройка
waitForATTUserAuthorization
на этапе инициализации приложения - Вызов
ATTrackingManager.requestTrackingAuthorization
каждый раз, когда должно отображаться окно с запросом согласия на ATT
Описание waitForATTUserAuthorization
Когда пользователь запускает приложение, ATT имеет статус notDetermined (Не определен). В течение времени ожидания waitForATTUserAuthorization
:
- SDK помещает в очередь в памяти событие запуска и последующие внутренние события приложения, аналогично тому, как регистрируются оффлайн-события
- Если пользователь разрешает сбор IDFA:
- SDK добавляет IDFA к кешированным событиям.
- SDK запускается и отправляет кешированные события с IDFA (не дожидаясь окончания времени ожидания).
- Если пользователь не разрешает сбор IDFA:
- SDK запускается и отправляет кешированные события без IDFA (не дожидаясь окончания времени ожидания).
- Если время ожидания истекло, а статус ATT остался notDetermined (Не определен), SDK запускается и отправляет кешированные события без IDFA.
Факторы, которые необходимо учитывать
- Если в течение времени ожидания пользователь переводит приложение в фоновый режим:
- Таймер приостанавливается, пока пользователь не вернется к окну приложения.
- События кэшируются в памяти.
- Если в течение времени ожидания пользователь прекращает работу приложения или закрывает его:
- Таймер перезапускается при следующем запуске приложения.
- Кэшированные события будут потеряны.
Подводные камни
-
waitForATTUserAuthorization
требуется для сбора IDFA в iOS 14.5 и выше. Если вызовwaitForATTUserAuthorization
отсутствует, события запуска приложения будут отправляться без IDFA. - Не вызывайте
start
в обратном вызовеrequestTrackingAuthorization
. В противном случае это может привести к неполной или некорректной атрибуции.
Настройте поддержку ATT в SDK для iOS
Чтобы настроить поддержку ATT в SDK для iOS:
-
В коде инициализации настройте
waitForATTUserAuthorization
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[AppsFlyerLib shared] setAppsFlyerDevKey:@"<AF_DEV_KEY>"]; [[AppsFlyerLib shared] setAppleAppID:@"<APPLE_APP_ID>"]; [[AppsFlyerLib shared] setDelegate:self]; [[AppsFlyerLib shared] waitForATTUserAuthorizationWithTimeoutInterval:60]; return YES; }
class AppDelegate: UIResponder, UIApplicationDelegate, AppsFlyerLibDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { AppsFlyerLib.shared().appsFlyerDevKey = "<AF_DEV_KEY>" AppsFlyerLib.shared().appleAppID = "<APPLE_APP_ID>" AppsFlyerLib.shared().delegate = self AppsFlyerLib.shared().waitForATTUserAuthorization(timeoutInterval: 60) ... } ... }
-
В коде приложения вызовите
ATTrackingManager.requestTrackingAuthorization
для отображения окна с запросом согласия на ATT. Например, если вы хотите показать пользователю запрос согласия после загрузки определенного представления:- (void)viewDidLoad { [super viewDidLoad]; if #available(iOS 14, *) { [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) { NSLog(@"Status: %lu", (unsigned long)status); }]; } }
override func viewDidLoad() { super.viewDidLoad() if #available(iOS 14, *) { ATTrackingManager.requestTrackingAuthorization { (status) in } } }
Этот вызов запускает окно с запросом согласия на ATT.
Настройка окна с запросом согласия на ATT
Настройка окна с запросом согласия на ATT
- Выберите файл
Info.plist
вашего проекта в навигаторе проектов Xcode. - Добавьте в список запись: Нажмите
+
рядом сInformation Property List
. - Прокрутите вниз и выберите
Privacy - Tracking Usage Description
. - В качестве
значения
добавьте текст, который вы хотите показать пользователю, когда запрашиваете разрешение на сбор данных IDFA.
Приложения для детей
Чтобы выложить ваше приложение в разделе Дети в App Store, компания Apple требует, чтобы приложение не "передавало персональную информацию или информацию об устройстве третьим лицам". Для выполнения этого требования вам нужно явным образом отключить фреймворки AdSupport и iAD.
Чтобы отключить фреймворки для рекламы:
-
disableCollectASA = true
. Узнать больше -
disableAdvertisingIdentifier = true
. Узнать больше
[AppsFlyerLib shared].disableCollectASA = YES [AppsFlyerLib shared].disableAdvertisingIdentifier = YES;
AppsFlyerLib.shared().disableCollectASA = true AppsFlyerLib.shared().disableAdvertisingIdentifier = true
Прекратить предоставлять данные партнерам
В некоторых случаях рекламодатели должны прекратить передачу рекламным сетям / партнерам данных по определенным пользователям. Причины могут быть следующие:
- Политики конфиденциальности, такие как CCPA или GDPR.
- Отказ пользователей от предоставления данных
- Конкуренция с некоторыми партнерами (рекламными сетями, третьими сторонами)
AppsFlyer предоставляет два метода API для прекращения обмена данными с некоторыми или всеми партнерами:
- setSharingFilterForAllPartners: Используется рекламодателями, чтобы прекратить предоставлять данные некоторым сетям/интегрированным партнерам.
- setSharingFilterForAllPartners: Используется рекламодателями, чтобы прекратить предоставлять данные всем сетям/интегрированным партнерам.
Эти методы фильтрации поддерживаются в SDK, начиная с версии V5.4.1.
Метод фильтрации должен вызываться каждый раз при инициализации SDK, он влияет на всю сессию.Если требуется время, чтобы определить, нужно ли устанавливать фильтры общего доступа, то отложите инициализацию SDK.
Если метод активирован до первого вызова start:
- Пользователи из SRN атрибутируются как органические, и их данные не передаются интегрированным партнерам.
- Пользователи по кликам из рекламных сетей (не SRN) правильно атрибутируются в AppsFlyer, но их данные не передаются в рекламные сети через постбэки, API, отчеты по сырым данным или каким-либо другим способом.
В настоящее время данные об удалении приложения нельзя фильтровать с помощью этих методов. Однако вы можете прекратить отправку событий удаления партнерам, настроив это на их страницах настройки в AppsFlyer.
continueUserActivity
Описание |
Вызывает onAppOpenAttribution , когда приложение открывается из Universal Link для iOS версии 9 и выше. |
Сигнатура метода |
|
Пример использования |
|
currencyCode
Описание |
Установите код валюты для событий с доходом. Принимаются коды валют ISO. |
Сигнатура метода |
|
Пример использования |
|
anonymizeUser
Описание |
Анонимизация установок, событий и сеансов пользователя. Дополнительные сведения см. в пунктеАнонимизация пользовательских данных. |
Сигнатура метода |
|
Пример использования |
|
disableCollectASA
Описание |
Начиная с версии SDK 4.8.11, AppsFlyer SDK динамически загружает рекламную программу Apple adSupport.framework. Эта инфраструктура необходима для регистрации и измерения эффективности кампаний Apple Search Ads для вашего приложения. Если вы не хотите, чтобы AppsFlyer динамически загружал эту платформу, установите для этого свойства значение true. |
Сигнатура метода |
|
Пример использования |
|
handleOpenUrl
Описание |
Этот метод сообщает схему URI в AppsFlyer SDK, когда приложение открывается с использованием диплинкинга со схемой URI. Этот метод находится внутри AppDelegate. |
Сигнатура метода |
|
Пример использования |
|
handlePushNotification
Описание |
Измерение и получение данных из кампаний с push-уведомлениями. Дополнительные сведения см. в разделе Измерение push-уведомлений. |
Сигнатура метода |
|
Пример использования |
|
isDebug
Описание |
Показать журналы AppsFlyer SDK в консоли Xcode. Отладка должна быть ограничена только фазой разработки. Не отправляйте приложение в магазин с включенным режимом отладки. Это несет большую угрозу безопасности и конфиденциальности. |
Сигнатура метода |
|
Пример использования |
|
isStopped
Описание |
Прекращение выполнения всех функций SDK. Подробные сведения см. в разделе озащите конфиденциальной информации пользователей, пункт "Отказ". |
Сигнатура метода |
|
Пример использования |
|
onAppOpenAttribution
Описание |
Получает данные с глубинными ссылками, когда приложение открывается по глубинной ссылке. |
Сигнатура метода |
|
Пример использования |
|
onAppOpenAttributionFailure
Описание |
Обработка ошибок получения данных по глубинным ссылкам. |
Сигнатура метода |
|
Пример использования |
|
onConversionDataSuccess
Описание |
Получение данных о конверсии после установки. Полезно для отложенного диплинкинга. Примечание. В SDK |
Сигнатура метода |
|
Пример использования |
|
onConversionDataFail
Описание |
Обрабатывает ошибки, когда не удается получить данные о конверсиях для установок. |
Сигнатура метода |
|
Пример использования |
|
didResolveDeepLink
Описание |
Позволяет направить пользователей мобильных устройств — как уже установивших, так и еще не установивших ваше приложение — на конкретное внутреннее действие после открытия этого приложения. Узнать больше |
Сигнатура метода |
|
performOnAppAttribution
Описание |
Позволяет разработчикам вручную перезапустить onAppOpenAttribution со специальной ссылкой (URI или URL), не регистрируя новое повторное вовлечение. Этот метод может потребоваться, если приложению необходимо перенаправить пользователей по указанной ссылке или получить короткий URL-адрес AppsFlyer, не сворачивая приложение. Это может потребоваться, поскольку обычно обратный вызов onAppOpenAttribution вызывается, только если приложение было открыто по диплинку. |
Сигнатура метода |
|
Пример использования |
|
registerUninstall
Описание |
Измерение количества удалений приложений. Измерение количества удалений для iOS-устройств. |
Сигнатура метода |
|
Пример использования |
|
resolveDeepLinkURLs
Описание |
Получение ссылки OneLink от доменов регистрации кликов. Дополнительные сведения см. в разделе Разрешение упакованных URL-адресов глубинных ссылок. |
Сигнатура метода |
|
Пример использования |
|
setAdditionalData
Описание |
Добавление дополнительных данных для отправки на внешние партнерские платформы. |
Сигнатура метода |
|
Пример использования |
См. настройка дополнительных пользовательских данных. |
setAppInviteOneLink
Описание |
Установка идентификатора шаблона OneLink, который используется для создания настраиваемых ссылок атрибуции для приглашений пользователей. |
Сигнатура метода |
|
Пример использования |
См. описание настройки ссылки OneLink для атрибуции приглашений пользователей. |
setAppleAppID
Описание |
Установите идентификатор приложения (для идентификатора itunes), чтобы SDK мог отправлять данные на правильную панель управления приложения. Используйте его при инициализации SDK. |
Сигнатура метода |
|
Пример использования |
|
appsFlyerDevKey
Описание |
Установите ключ разработчика AppsFlyer так, чтобы SDK мог отправлять данные на нужную панель инструментов приложения. Используйте его при инициализации SDK .Чтобы узнать, как получить ваш ключ разработчика, см. здесь . |
Сигнатура метода |
|
Пример использования |
|
Установка Customer User ID
Описание |
Настройка Customer User ID. Дополнительные сведения см. в пунктеУстановка Customer User ID. |
Сигнатура метода |
|
Пример использования |
setPartnerData
Описание |
Партнеры и рекламодатели могут включать дополнительные данные в события SDK. |
Сигнатура метода |
|
Пример использования |
|
setSharingFilter
Описание |
Используется рекламодателями, чтобы задать несколько сетей/интегрированных партнеров, которым нужно прекратить предоставлять данные. |
Сигнатура метода |
|
Пример использования |
|
setSharingFilterForAllPartners
Описание |
Используется рекламодателями, чтобы прекратить предоставлять данные всем сетям/интегрированным партнерам. |
Сигнатура метода |
|
Пример использования |
|
setShouldCollectDeviceName
Описание |
Должен ли SDK собирать имя устройства. По умолчанию установлено значение false. |
Сигнатура метода |
|
Пример использования |
|
setUseUninstallSandbox
Описание |
Чтобы проверить деинсталляции для приложений, которые все еще находятся в разработке (еще не опубликованы в Apple App Store), установите для этого свойства значение true. |
Сигнатура метода |
|
Пример использования |
|
startWithCompletionHandler
Описание |
Проверьте, успешно ли выполнен start . Вы можете использовать собственную логику, чтобы отработать успешный или неудачный запуск SDK. |
Сигнатура метода |
|
Пример использования |
См. раздел проверка успешного запуска SDK. |
logEvent
Описание |
Отправка в AppsFlyer внутренних событий приложения. Подробные сведения см. в разделе орегистрации внутренних событий приложения. |
Сигнатура метода |
|
Пример использования |
|
validateAndLogInAppPurchase
Описание |
Установите ключ разработчика AppsFlyer так, чтобы SDK мог отправлять данные на нужную панель инструментов приложения. Чтобы узнать, как получить ваш ключ разработчика, см. здесь . Используйте его при инициализации SDK . |
Сигнатура метода |
|
Пример использования |
См. Проверка покупок в приложении |
disableAdvertisingIdentifier
Описание |
Начиная с версии SDK 4.8.11, AppsFlyer SDK динамически загружает рекламную программу Apple adSupport.framework. Эта инфраструктура необходима для сбора идентификаторов IDFA на устройствах для целей атрибуции. Если вы не хотите, чтобы AppsFlyer динамически загружал эту платформу, установите для этого свойства значение true. |
Сигнатура метода |
|
Пример использования |
[AppsFlyerLib shared].disableAdvertisingIdentifier= YES; AppsFlyerLib.shared().disableAdvertisingIdentifier = true |
waitForATTUserAuthorization
Описание |
Используйте этот метод, если хотите собирать IDFA на устройствах iOS 14.5+ путем запроса авторизации пользователя. Если пользователь дает согласие, IDFA передается в SDK. Пользователю дается определенное время (период ожидания), чтобы он мог разрешить или запретить сбор IDFA. Когда это время истекает, данные IDFA не собираются. Подробнее см. в статье Настройка поддержки ATT. |
Сигнатура метода |
|
Пример использования |
|
start
Описание |
После вызова этого API запускается SDK, сеансы будут немедленно отправлены, и все переходы из фонового режима в активный будут записываться как сеанс. |
Сигнатура метода |
|
Пример использования |
|
logLocation
Описание |
Зарегистрируйте местоположение пользователя вручную. |
Сигнатура метода |
|
Пример использования |
|
appendParametersToDeepLinkingURL
Описание |
Позволяет владельцам приложений использовать для диплинкинга универсальные ссылки (без OneLink), чтобы атрибутировать сессии, инициированные через домен, связанный с их приложением. Вызовите этот метод до вызова start. Для метода нужно:
|
Сигнатура метода |
|
Пример использования |
|
addPushNotificationDeepLinkPath
Описание |
Настройте, как SDK будет извлекать значения диплинков из полезных данных push-уведомлений. |
Сигнатура метода |
|
Пример использования |
Этому вызову соответствует следующая структура полезной нагрузки:
|
disableSKAdNetwork
Описание |
Позволяет отключить атрибуцию в SKAdNetwork. Для отключения установите значение true . |
Сигнатура метода |
|
Пример использования |
|
Комментарии
Войдите в службу, чтобы оставить комментарий.