概览: AppsFlyer iOS SDK V6.X, 后文简称SDK, 提供iOS端的归因和事件上报等功能,且支持iOS14相关变化。 请格外注意:该版本系列中涉及的核心API名称,相较于之前版本,进行了重要更新。
重要信息!
iOS SDK V5.4.4 在基础功能层面完全兼容 iOS 14.但是,我们强烈建议您采用SDK V6.X版本以确保兼容iOS14的重要变化和未来更新。查看 升级至 iOS SDK V6.
请注意SDK V6.0.8 或未来以上版本会支持Apple App Clips 归因。
1. 概述
该版本仍会继续提供激活归因,事件归因,数据报告等功能。该SDK全面,安全,轻巧且易于嵌入。
您可以记录激活,会话(session)和应用内事件等相关数据,从而完整轻松衡量ROI和应用内用户行为数据。
iOS 版本 | 支持的归因方式 |
---|---|
iOS 13 及更低版本 |
|
iOS 14 及更高版本 |
|
* iOS SDK V5.4和更早版本:
|
1.1 SDK集成-您需要做什么
选项卡 | 目的 | 结果 |
---|---|---|
SDK整合 |
显示如何添加和配置SDK。 |
|
核心API |
展示如何使用SDK的核心API。这些API可让您衡量应用内事件和收入,执行深层链接并收集转化数据。 |
使应用内事件和收入显示在控制面板上 实现深度链接 |
展示如何导入和使用可选的API,例如卸载度量,引荐(用户邀请归因)和推送通知。 |
你可以去衡量卸载,引荐,用户与推送通知的互动,处理用户隐私以及更多其他功能。 |
|
开发人员SDK API的快速参考 |
|
1.2 SDK与iOS的兼容性
- SDK:
- 兼容所有iOS和tvOS设备(iPhone,iPod,iPad,Apple TV),前提是iOS版本6或以上,tvOS版本9或以上;
- 支持Apple IPv6 DNS64/NAT64 网络。
注意
苹果的iOS14 的App Clips即将很快上线!
请通过我们的 开发者App Clips权威指南了解全部信息
该小节会为开发人员说明如何配置SDK初始化。完成上述配置后,后台将会有两个激活数据,一个自然激活,一个非自然激活。
2.将SDK添加到您的应用中
2.1 在Xcode中下载并添加SDK
- 下载并安装 最新版本的CocoaPods.
- 添加下行至
Podfile
:
pod 'Beta-AppsFlyerFramework'
- 运行
pod install
。 - 从此处开始,使用
.xcworkspace
文件打开 Xcode 中的项目,而不是使用.xcodeproj
文件打开。
注意
如果您正在开发tvOS应用程序,则CocoaPods会自动从AppsFlyerFramework中添加相关的依赖项。
- 下载最新版本的 Carthage.
- 将下面一行添加到Cartfile Binary
https://raw.githubusercontent.com/AppsFlyerSDK/AppsFlyerFramework/master/Carthage/appsflyer-ios.json
注意
上面的链接链接到静态库。如果你更新了一个新的IOS版本,请执行如下操作:
- 在Xcode中的copy-framworks中移除 运行脚本 。
- 确保未嵌入库。
了解更多,请查阅 Carthage docs.
目前不支持tvOS应用程序
-
下载 iOS SDK 用作静态框架。
要验证sdk静态框架的完整性,请点击这里。 - 解压刚刚下载的 AppsFlyerLib.framework.zip文件。
- 将 AppsFlyerLib.framework拖放到 Xcode 项目中。
- 确保已经选中 Copy items if needed。
注意
本方法仅兼容 iOS 8 及更高版本。
对于tvOS类应用程序,你需要一个不同的AppsFlyerFramework
- 克隆 AppsFlyerFramework。
- 在 AppsFlyerFramework的文件夹中找到AppsFlyerLib.framework。
- 重复步骤3和4.
2.2原生iOS框架dependencies
SDK会自动添加并使用以下原生框架:
- AdSupport.framework
- 必须要有此框架才能从设备中收集 IDFA。
缺少IDFA将无法对Facebook Ads,Twitter,Google ads以及其他networks的安装进行归因。 - iAd.framework
- 记录Apple Search Ads的投放数据。
- AdServices框架(
V6.1.3+
) - 记录Apple Search Ads的投放数据。
如果你想移除frameworks并且禁用IDFA收集。
- 禁用IDFA收集
- 禁用iAd.framework
严格模式SDK
使用严格模式SDK可以完全删除收集IDFA的功能和AdSupport框架dependencies(例如,在为儿童开发应用时)。
在您的Podfile
中,将AppsFlyerLib
dependency替换为:
pod 'AppsFlyerFramework/Strict','6.1.1'
注意:如果使用strict模式SDK并调用disableAdvertisingIdentifier
,会收到编译错误。
注意
如果您使用的SDK版本早于4.10.4,您需要手动添加ad support frameworks。
手动添加ad support frameworks。
- 在您的Xcode项目中,选择项目目标。
- 选择目标的 General 选项卡。
- 展开 Linked Frameworks and Libraries 部分。
- 点击 + 来添加一个framwork。
- 搜索 AdSupport.framework
- 从列表中选择AdSupport.framework。
为iAd.framework重复上述过程。
3.配置并初始化SDK
本节介绍如何初始化AppsFlyer Android SDK。
3.1 检索你的dev key
AppsFlyer使用唯一的dev key来标识您的帐户。dev key是强制性的,因为它允许SDK安全地发送和检索属于您AppsFlyer帐户的数据。
要获取SDK密钥:
- 在AppsFlyer面板中, 进入 配置 > 应用配置.
- 复制您的dev key。
3.2初始化SDK
注意
要支持使用 SceneDelegate
iOS应用,请参阅 使用SceneDelegate 初始化SDK。
以下代码为示例。请您确保正确替换<AF_DEV_KEY>
和<APPLE_APP_ID>
里的占位符。
在AppDelegate.h
中文件:
- 导入
AppsFlyerLib/AppsFlyerLib.h
header。 - 将
AppsFlyerLibDelegate
添加到AppDelegate
接口声明中。
#import <UIKit/UIKit.h>
#import <AppsFlyerLib/AppsFlyerLib.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, AppsFlyerLibDelegate>
@end
在AppDelegate.m
文件:
- 在
didFinishLaunchingWithOptions
中,配置:- AppsFlyer dev key
- app ID
- 其他设置
- Override
onConversionDataSuccess
和onConversionDataFail
回调以便处理激活转换数据并启用延迟深度链接。 - 覆盖
onAppOpenAttribution
和onAppOpenAttributionFailure
回调以处理归因并启用直接深度链接。 - 在
didReceiveRemoteNotification
回调中,调用handlePushNotification
处理push notification类型的老用户召回(re-engagements)转化归因。 - 在
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
文件中:
- 导入
AppsFlyerLib
。 - 将
AppsFlyerLibDelegate
添加到AppDelegate
类声明中。 - 在
didFinishLaunchingWithOptions
中,配置:- AppsFlyer dev key
- app ID
- 其他设置
- Override
onConversionDataSuccess
和onConversionDataFail
回调以便处理激活转换数据并启用延迟深度链接。 - 覆盖
onAppOpenAttribution
和onAppOpenAttributionFailure
回调以处理归因并启用直接深度链接。 - 在
didReceiveRemoteNotification
回调中,调用handlePushNotification
处理push notification类型的老用户召回(re-engagements)转化归因。 - 在
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使用SceneDelegate初始化SDK
仅在使用SceneDelegate
的情况下,采用该初始化方法。
由于使用SceneDelegate
的时候不会调用applicationDidBecomeActive
,可使用UIApplicationDidBecomeActiveNotification
作为备选方案进行初始化SDK,如下图示例。
以下代码为示例。请您确保正确替换<AF_DEV_KEY>
和<APPLE_APP_ID>
里的占位符。
在AppDelegate.h
中文件:
- 导入
AppsFlyerLib/AppsFlyerLib.h
header。 - 将
AppsFlyerLibDelegate
添加到AppDelegate
接口声明中。
#import <AppsFlyerLib/AppsFlyerLib.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, AppsFlyerLibDelegate>
@end
在AppDelegate.m
文件:
- 在
didFinishLaunchingWithOptions
回调中,配置:- AppsFlyer dev key
- app ID
- 其他设置
- Override
onConversionDataSuccess
和onConversionDataFail
回调以便处理激活转换数据并启用延迟深度链接。 - 覆盖
onAppOpenAttribution
和onAppOpenAttributionFailure
回调以处理归因并启用直接深度链接。 - 在
didReceiveRemoteNotification
回调中,调用handlePushNotification
处理push notification类型的老用户召回(re-engagements)转化归因。 - 在
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;
/* Set isDebug to true to see AppsFlyer debug logs */
[AppsFlyerLib shared].isDebug = true;
// Use UIApplicationDidBecomeActiveNotification to start the SDK
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sendLaunch:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
return YES;
}
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)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts API_AVAILABLE(ios(13.0)){
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 *)session options:(UISceneConnectionOptions *)connectionOptions {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
NSUserActivity *activity = [[connectionOptions userActivities] allObjects].firstObject;
if (activity) {
[self scene:scene continueUserActivity:activity];
}
[self scene:scene 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 *)scene 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 *)scene 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 *)scene API_AVAILABLE(ios(13.0)){
// 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
文件中:
- 导入
AppsFlyerLib
。 - 将
AppsFlyerLibDelegate
添加到AppDelegate
类声明中。 - 在
didFinishLaunchingWithOptions
回调中,配置:- AppsFlyer dev key
- app ID
- 其他设置
- Override
onConversionDataSuccess
和onConversionDataFail
回调以便处理激活转换数据并启用延迟深度链接。 - Override
onAppOpenAttribution
和onAppOpenAttributionFailure
回调以便处理归因数据,并启用深度链接。 - 在
didReceiveRemoteNotification
回调中,调用handlePushNotification
处理push notification类型的老用户召回(re-engagements)转化归因。 - 在
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
文件中:
- 导入
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) {
// Processing Universal Link from the killed state
if let userActivity = connectionOptions.userActivities.first {
self.scene(scene, continue: userActivity)
}
// Processing URI-scheme from the killed state
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使用的一个类(class),用于验证广告推广所获取的新增用户的激活(install)数据。整个应用激活的验证流程涉及流量方应用和广告主应用。
流量方应用指的是通过广告平台展示签名广告的一方。如何配置广告展示并不在AppsFlyer SDK可控制的范围内。如需进行相关配置,请按照Apple的说明进行操作。
对于广告主应用(即集成AppsFlyer SDK的应用),AppsFlyer SKAdNetwork解决方案使用SKAdNetwork来提供归因数据回调,与此同时,AppsFlyer会在保护用户隐私的前提下,收集,翻译并聚合数据。首次启动应用时,AppsFlyer SDK会根据客户市场人员在AppsFlyer后台的配置,设置SKAdNetwork的转换值(conversion value)。
- 开发人员无需操作。
-
AppsFlyer SDK会自动调用必要的SKAdNetwork API,即
registerAppForAdNetworkAttribution()
和updateConversionValue()
。开发人员请勿再单独调用。 - 不要让其他SDK调用SKAdNet API。这样做可能会延迟iOS将回发发送到AppsFlyer的时间,并更改我们用于计算SKAdNetwork信息中心用户质量指标的conversion value。
- 广告主需要在其AppsFlyer面板配置SKAdNetwork功能
客户开发人员或市场人员无需在应用商店中进行任何操作或注册。
如要禁用SKAdNetwork归因,请使用disableSKAdNetwork API 。
3.6 SDK延迟初始化
在某些场景下(例如GDPR或COPPA授权),您可能需要等到终端用户授权,再进行SDK初始化,即延迟初始化。
注意:此处与iOS 14中的ATT无关。
如需延迟SDK初始化:
- 防止 在后台到前台过度期间发送会话。 在 sendLaunch() 方法中 (在每次 applicationDidBecomeActive 时调用(如先前到3.3 初始化SDK), 利用条件检查包装到
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集成。
添加您的设备为测试设备
在开始测试安装之前:
- 确保您的设备未安装该应用。
- 将您要在上面测试的设备添加为测试设备 。
4.2模拟自然激活
自然安装是未被归因的安装,通常是直接前往应用商店安装的用户。
要模拟自然安装:
- 确保已将移动设备连接到计算机。
- 在 Xcode 中,打开debug终端
- 从 Xcode Studio里,将App安装到设备或者虚拟机上。
- 等待应用启动。
- 在debug终端中,查找应用包名。
您应该看到以下内容:
日志中的 Send start() 表示SDK上报了一个安装。该数据来自于app delegate中的 onConversionDataSuccess
方法。Getting conversion data将稍后在本篇文档讨论。
注意: 从SDK Version 第5版开始, onConversionDataSuccess
是获取转化数据方法的名称。如果使用的SDK版本低于5.0.0,则该方法的名称为 onConversionDataReceived
。我们建议您升级到SDK 5.0.0。要了解更多信息,请点击这里 。
自然激活应该出现在AppsFlyer后台的 数据总览 面板。
如果您没有在AppsFlyer后台看到激活数据,请参阅我们的 SDK故障排查指南 。
4.3模拟非自然激活
非自然安装通常是在广告互动之后的可归因安装。您可以使用归因链接模拟非自然安装。
如何找到Dev Key:
- 找出您app的 itunes ID,例如 id123456789.
- 在下面的链接中, 将 <APP_ID> 替换为您app的 itunes ID:
例如: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。
- 如果该应用已在应用商店上架,那您将跳转至应用商店。不要 从app store下载app。继续执行步骤5。
- 如果该应用未在应用商店上架并且仍在开发中,则屏幕会显示‘在应用商店中找不到这个应用’。继续执行步骤5。
- 在 Xcode Studio 中,打开debug终端
- 使用USB数据线将设备连接到计算机。
- 通过 Xcode,将app安装到设备上。
- 在debug终端中,寻找您app的itunes ID。
您应该看到以下内容:
非自然激活应该出现在AppsFlyer后台的 数据总览 面板。
注意
当您已经测试并调试了SDK接入后,请关闭 SDK logs.
此标签说明了如何记录应用内事件和收入、以及如何设置深度链接。
记录应用内事件和收入可让您衡量用户质量。深度链接可以为用户提供更好的用户体验。
该选项卡是给开发人员的说明,但是市场营销人员的参与也必不可少,原因如下:
- 应当由市场营销人员决定需要记录的应用内事件以衡量用户质量。
- 市场营销人员必须要有访问AppsFlyer控制面板的权限才可以设置OneLink进行深度链接。
5.记录应用内事件
应用内事件可助您深入了解应用里正在发生的事。我们建议您花些时间定义要记录的事件。记录应用内事件有助于您衡量KPI,例如ROI(投资回报率)和LTV(生命周期价值)。
有几种方法可以记录应用内事件。最常见的方法是通过我们在本文中讨论的通过SDK发送事件。要了解其他记录应用内事件的方法,请参见我们的应用内事件概述指南 。
如果您的应用属于某个行业,例如旅行、游戏、电子商务等,您可以参考每个行业的推荐应用内事件列表。
5.1应用内事件名称和参数
SDK包含两种常见参数,他们用来表示与应用内事件相关的信息。
- Event names - 应用内事件名字通常用
AFEventEventName
来表示。
例如AFEventPurchase
,AFEventAddToCart
。 - Event parameters - 应用内事件参数通常用
AFEventParameterParameterName
来表示。
例如AFEventParameterRevenue
,AFEventParamaterContentId
。
出于一下原因,我们强烈建议使用这些接口:
- 标准命名使得AppsFlyer可以将事件自动映射到SRN,例如Facebook,Google,Twitter和Snapchat。
- 向后兼容-如果AppsFlyer决定更改任何事件或事件参数的名称,则您的实现是向后兼容的。
要使用这两个接口,请导入AppsFlyerLib.h如果使用Objective-C,或者是Swift的AppsFlyerLib
请将下面一行放置在 class implementation file里。
#import AppsFlyerLib.h
请将下面一行放置在 Swift class file里。
import AppsFlyerLib
这里是推荐事件名称和结构列表 。
5.2记录收入
您可以通过任何应用内事件发送收入。通过 af_revenue
(AFEventParameterRevenue
) 这两个事件参数来将收入包含在应用事件中。您可以使用任何数值(正数或负数)填充它。
af_revenue
是AppsFlyer原始数据和控制面板上唯一统计为真实收入的事件参数。了解更多详细信息,请点击此处。
发送收入事件时,请记住以下几点:
- 如果设置货币代码(请参见下面的示例),则该代码应为 3个字符的ISO 4217代码 。(默认值为美元)。
- 你可以通过调用以下方法为所有事件设置货币代码
- 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"
]);
上述purchase event包含200美金收入,会作为收入显示在Dashboard面板上。
记录负收入
在某些情况下,您想记录负收入。
例如,一名用户收到了一笔退款或者取消了订阅。
[[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应用内购买验证
AppsFlyers SDK为应用内购买提供服务器验证。通过调用 validateAndLogInAppPurchase
来检验一次购买事件。
该方法调用将自动生成一个 af_purchase
应用内事件。
此调用方法有两个回调模块,一个用于“成功”,另一个用于“失败”(可能是任何原因,包括验证失败)。成功后, 将返回一份典目(dictionary), 其中包含 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
}
注意
调用 validateAndLogInAppPurchase
会自动生成一个af_purchase 应用内事件。如果广告主同时创建该事件,会造成重复上报。
5.4 应用内事件限制
- 事件名称:最多45个字符
- 事件值:不得超过1000个字符-如超过这个长度,我们可能会截断它
- 定价和收入:仅使用数字和小数点,例如5或5.2
- 价格和收入最多可以到小数点后5位,如5.12345
- 从Android SDK V4.8.1开始,应用内事件和其他SDK API都支持非英语字符。
5.5 记录应用内事件的示例
你可以通过调用 logEvent
来记录包含事件名字和事件值的应用内事件。查看 In-App Events 文档来了解更多细节。
以下是有关如何记录购买事件的简单示例。关于每个行业的现成代码片段列表,请参阅详细应用内事件指南
示例:应用内购买活动
[[AppsFlyerLib shared] logEvent:AFEventPurchase
withValues: @{
AFEventParamRevenue: @200,
AFEventParamCurrency: @"USD",
AFEventParamQuantity: @2,
AFEventParamContentId: @"092",
AFEventParamReceiptId: @"9277"
}];
注意
- 传递给event SDK的字典格式事件值,必须对 NSJSONSerialization. 的JSON转换有效的。有关更多信息,请参见这里 。
- 对于收入, 不要添加任何货币符号, 因为这些符号是不被识别的。
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 |
"事件超时,检查'minTimeBetweenSessions'参数" |
11 |
“正在跳过事件,因为启用了'isStopTracking'” |
40 |
网络错误:错误说明来自Android |
41 |
“没有dev key” |
50 |
"状态代码错误"+实际服务器响应代码 |
6. 用OneLink进行深度链接
OneLink是AppsFlyer的对平台归因、 跳转和深度链接的解决方案。
6.1设备检测和跳转
OneLink在设备点击时检测到设备类型,并将用户跳转到匹配的目的地,例如Google Play商店、iOS应用商店、第三方应用商店、或者网页。
OneLink跳转指南讨论了如何实现多平台归因链接(无需SDK编码)。这也是深度链接的基础。
6.2 深度链接
深度链接使您可以将用户发送到特定活动,并为他们提供自定义内容。该功能在运行再营销广告系列时特别有用。
要运用OneLink进行深度链接, 有权访问AppsFlyer控制面板的市场营销人员和有权访问该应用的开发人员必须共同合作 。
请参阅我们的用于深度链接的URI Scheme设置指南 。
6.3 延迟深度连结
延迟深度链接可以使您将深度链接用于新用户上面,当用户首次启动app的时候引领他们到指定页面。这不同于常规的深度链接,在常规深度链接中,应用必须已经安装在用户设备上。
要用OneLink实现延迟深度链接,开发人员需要有访问AppsFlyer控制面板的权限。
延迟深度链接的设置与深度链接相同。唯一的区别是,您需要在应用中实现其他逻辑,以便在用户安装和启动应用后将他们深度链接到自定义内容。
请参阅深度链接设置指南了解更多信息。
6.4 获取深度链接数据
在每次安装或深度链接发生后,SDK都会为您提供转化或互动数据。您可以使用此数据并配置代码逻辑来触发自定义内容或应用内的特定活动
当深度链接直接打开应用程序时想要获取深度链接数据,请配置onAppOpenAttribution 。
要随时手动获取深度链接的再互动数据,请配置performOnAppAttribution 。这将允许访问re-engagement数据, 而不会算作一个新的re-engagement转化 。
请参阅深度链接设置了解更多信息。
6.5配置推送通知深度链接方案
addPushNotificationDeepLinkPath
方法为应用开发者提供了灵活的界面,用于从推送通知payload中提取深度链接。
默认情况下,SDK会在推送通知的JSON
payload的中寻中af
的深度链接参数。许多推送通知供应方会使用他们各自专有的JSON
格式,这种情况下,如果不进行额外配置,SDK将无法解析。
通过addPushNotificationDeepLinkPath
,您可以配置SDK应读取推送通知JSON payload中的哪个参数作为深度链接参数。
如果您使用的推送通知供应方的JSON payload不是SDK默认可读取的格式,可采用此方法。
调用addPushNotificationDeepLinkPath
,SDK会验证以下内容:
- payload中包含所需密钥。
- 参数中包含有效的OneLink URL。
基础配置
针对addPushNotificationDeepLinkPath
,参考以下调用方法
[AppsFlyerLib shared] addPushNotificationDeepLinkPath:@[@"deeply", @"nested", @"deep_link"]]
AppsFlyerLib.shared().addPushNotificationDeepLinkPath(["deeply", "nested", "deep_link"])
和场景:
场景1
您的应用是通过推送通知唤起的。包含的payload结果如下。
{
...
"deeply": {
"nested": {
"deep_link": "https://yourdeeplink2.onelink.me"
}
}
...
}
在这种情况下,SDK会自动提取deep_link
的值并执行深度链接。
场景2
您的应用是通过推送通知唤起的。包含的payload结果如下。
{
...
"deeply": {
"nested": {
"banana": "https://yourdeeplink2.onelink.me"
}
},
...
}
在这种情况下,SDK在payload中找不到deep_link
参数。因此,不会发生任何事。
场景3
您的应用是通过推送通知唤起的。包含的payload结果如下。
{
...
"deeply": {
"nested": {
"deep_link": "Corrupted url or regular string"
}
},
...
}
在这种情况下,尽管SDK找到了deep_link
参数,但深度链接值无效。因此,执行上述调用时,也不会发生任何事。
高阶配置
要配置多个可能的payload结构,请多次调用addPushNotificationDeepLinkPath
:
- 首次调用中提供的深度链接会被使用,
- 其他调用会被忽略
如果没有找到任何可匹配的payload结构,或者payload中不包含OneLink链接,那么什么也不会发生。
例如,请参考以下payload
{
...
"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中获取AppsFlyer的转化数据,请导入如下代码:
- (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 Version 第5版开始,
onConversionDataSuccess
是获取转化数据方法的名称。如果使用的SDK版本低于5.0.0,则该方法的名称为onConversionDataReceived
。我们建议您升级到SDK 5.0.0。要了解更多信息,请点击这里 。 -
onAppOpenAttribution
在启动现有应用时(手动或通过深度链接)提供再营销的转化数据。
要了解有关转化数据的更多信息,请参见关于转化数据方案指南。
8.归因
设置 SDK 启动 Handler
如果您想要接收 SDK 成功启动并发送给 AppsFlyer 服务器的确认消息,请接入startWithCompletionHandler
handler。您可以用逻辑来判断处理 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
}
})
如果在请求listener的期间事件发生错误,错误代码和字符串说明如下,请参考:
错误代码 | 字符串解释 |
---|---|
10 |
"事件超时,检查'minTimeBetweenSessions'参数" |
11 |
“正在跳过事件,因为启用了'isStopTracking'” |
40 |
网络错误:错误说明来自Android |
41 |
“没有dev key” |
50 |
"状态代码错误"+实际服务器响应代码 |
设置其他自定义数据
setAdditionalData
API需要在SDK级别上与多个外部合作伙伴平台集成,包括Segment , Adobe和Urban Airship。
只有 平台的集成文档明确规定需要 setAdditionalData
API时,才使用此API。
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
归因网站(domains)产生的App 会话
广告主使用通用链接进行深层链接(不使用OneLink)并且拥有 与该App相关的domain 可以使用 appendParametersToDeepLinkingURL
方法将通过此domain发起的会话归因于该domain。
例如:一个用户通过google搜索并点击了你的domain,www.example.com:
- 如果用户未安装应用程序,则将他们定向到网站(www.example.com)。
- 如果用户已经在其设备上安装了该应用程序,则他们将被深层链接到与www.example.com关联的应用程序。会话归因于
appendParametersToDeepLinkingURL
指定的媒体源(pid
参数)。
更多信息,请参见iOS SDK参考。
注意:添加智能横幅以将网站访客转换为app用户。
9. 会话
自定义会话间的时间
默认情况下,在2次应用启动之间必须至少间隔 5秒,才能将其计为2次独立的应用启动 (更多有关应用启动计数的信息)。
使用以下API设置会话之间的最短时间:
[AppsFlyerLib shared].minTimeBetweenSessions = <your_custom_time_in_seconds>;
AppsFlyerLib.shared().minTimeBetweenSessions = <your_custom_time_in_seconds>
将两次启动之间的自定义时间设置为高值 可能严重影响依赖会话数据的API (例如深度链接) 。
面向实用应用的后台会话
在 iOS 中不可用。
10.自有媒体
解析包裹过的深度链接 URL
某些第三方服务(例如电子邮件服务提供商用他们自己的点击记录域名把链接包在电子邮件中。有些甚至允许您设置自己的点击记录域名。如果OneLink包在此类域名中,则可能会限制其功能。
要解决此问题,您可以使用 setResolveDeepLinkURLs
API。使用此API从启动应用程序的点击域中获取OneLink。请确保在 SDK 初始化之前调用此 API。
例如,您有三个点击域跳转到您的OneLink,即https://mysubdomain.onelink.me/abCD。使用此API获取您跳转至的OneLink的click domains,此API方法将接收SDK解析的域列表。
[AppsFlyerLib shared].resolveDeepLinkURLs = @[@"example.com",@"click.example.com"];
AppsFlyerLib.shared().resolveDeepLinkURLs = ["example.com", "click.example.com"]
上面的代码使您可以在保留OneLink功能的同时使用点击域名。点击域名负责启动应用。该API会从这些点击域名中获取OneLink,然后您可以使用此OneLink中的数据进行深度链接和自定义用户内容。
记录推送通知
借助AppsFlyer,您可以记录作为再营销广告重要部分的推送通知。
要使用此功能,请在 AppDelegate.m内部调用handlePushNotificationData
。
-(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)
}
有关推送通知测量的更多信息,请参阅此处 。
用户邀请归因
允许您的现有用户邀请他们的朋友和联系人作为新用户加入应用,这可能是应用增长的关键因素。使用AppsFlyer,您可以在应用中归因和记录源自用户邀请的安装。
有关详细信息,请参见用户邀请归因文章 。
交叉推广归因
11. 用户标识符
获取AppsFlyer ID
App的每次新安装都会创建一个唯一的AppsFlyer ID你可以该ID去实现多种目的:
- 发送服务器到服务器应用内事件 。
- 匹配您后台系统中的用户
- 合并 pull 和 push API 时的映射条目。
使用下列 API 获取唯一ID:
NSString *appsflyerId = [AppsFlyerLib shared].getAppsFlyerUID;
let appsflyerId = AppsFlyerLib.shared().getAppsFlyerUID()
设置客户用户 ID
设置您的 Customer User ID:
[AppsFlyerLib shared].customerUserID = @"my user id";
AppsFlyerLib.shared().customerUserID = "my user id"
在IOS中,如果想让每次app启动都带有Customer User ID都话,我们建议在应用初始化后尽早设置Customer User ID,因为它仅会关联设置之后上报的事件:
- 如果在调用
start
之前调用setCustomerUserId
,则Customer User ID将出现在激活和应用内事件的原始数据报告中。 - 如果在此之后设置,则“Customer User ID”仅关联该设置之后记录的事件。
获取客户用户 ID
为避免在首次启动后再次设置“Customer User ID”值,并减少向服务器请求Customer User ID的次数,可以使用以下方法检查其值是否为空:
NSString *customerUserID = [AppsFlyerLib shared].customerUserID;
let customerUserID = AppsFlyerLib.shared().customerUserID
了解客户用户 ID 的更多信息,请点击此处。
为 customerUserID 延迟 SDK 初始化
您可以延迟SDK初始化,直到生成了customerUserID。如果您想让安装和事件数据中都包含您的customer user ID,这将是十分有用的。
执行下列代码:
- (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初始化延迟到客户用户ID可用之后的更多信息,请在此处 。
警告
仅在适合您的业务逻辑的情况下使用此 API。使用此 API 会提高数据差异的几率,并且可能使应用更容易暴露于诈骗中。
12. 用户隐私
退出
在某些极端情况下,您可能出于法律和隐私合规方面的考虑,需要关闭所有 SDK 数据记录。这可以通过isStopped属性来实现。将此属性设置为true后,SDK将停止运行,并且不再与AppsFlyer服务器通信。
有几种不同的方案为用户选择退出。我们强烈建议您遵循与你的应用相关的方案的确切说明。
警告
仅在要从所有记录中完全忽略该用户的情况下,才使用isStopped API。使用此 API 将严重影响您的归因、数据收集以及 深度链接 机制。
[AppsFlyerLib shared].isStopped = true;
AppsFlyerLib.shared().isStopped = true
在任何情况下,可调用相同 API 以重新激活 SDK,但会传递 False。
重要信息!
如果isStopped
设置为true
则不要调用start
要再次开始记录数据,请将isStopped
设置为false
。
匿名用户数据
在 SDK 初始化过程中,使用该 API 明确匿名用户安装、事件和互动:
[AppsFlyerLib shared].disableAdvertiserIdentifier= YES;
[AppsFlyerLib shared].disableAdvertiserIdentifier== true
可以通过将anonymizeUser
设置为false来重新启动记录数据。
警告
对用户匿名会严重影响您的归因信息。只在法律要求您不得收集用户信息的地区使用此选项。
3.支持AppTrackingTransparency(ATT)
苹果消息表明,将来,iOS 14将强制要求用户授权以收集IDFA。
当前,默认情况下收集IDFA。但是,对于iOS 14及更高版本,您可以选择通过同意对话框请求用户授权以收集IDFA。如果用户选择退出,则不会收集IDFA。超时间隔会延迟将请求发送到AppsFlyer服务器。计时器到期后,将发送请求。
要请求用户授权收集IDFA,请在start()
之前添加以下代码:
//以下模块适用于希望为用户提供阻止IDFA收集的选项的应用程序。
//对于iOS 14及更高版本-可以提示用户阻止IDFA收集。
//如果用户选择退出,则SDK不会收集IDFA。
// for iOS 13 and below - The IDFA will be collected by the SDK.不会提示用户阻止收集。
if #available(iOS 14,*){
//设置SDK超时以等待IDFA收集,然后再处理应用启动
// //如果超时在用户要求阻止IDFA收集之前到期,则将收集IDFA。
[[AppsFlyerLib共享] waitForATTUserAuthorizationWithTimeoutInterval:60];
//向用户显示Apple IDFA同意对话框
(AppTrackingTransparency)
//必须在start()之前调用此处,以防止SDK收集IDFA
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
//....
} ];
}
//以下模块适用于希望为用户提供阻止IDFA收集的选项的应用程序。
//对于iOS 14及更高版本-可以提示用户阻止IDFA收集。
//如果用户选择退出,则SDK不会收集IDFA。
//对于iOS 13及以下版本-IDFA将由SDK收集。不会提示用户阻止收集。
if #available(iOS 14,*){
//设置SDK超时以等待IDFA收集,然后再处理应用启动
// //如果在用户要求阻止IDFA收集之前到期超时,则将收集IDFA。
AppsFlyerLib.shared().waitForATTUserAuthorization(timeoutInterval:60)
//向用户显示Apple IDFA同意对话框(AppTrackingTransparency)
//必须在start()之前在此处调用,以防止SDK收集IDFA
ATTrackingManager.requestTrackingAuthorization { (status) in
}
}
如何配置在弹出窗口中显示给用户的文本:
- 选择项目
Info.plist
在Xcode项目浏览器(Navigator)中。 - 在列表中添加一个条目:按
+
,在Information Property List
旁边。 - 向下滚动并选择
Privacy - Tracking Usage Description
。 - 将在征求收集IDFA的权限时要向用户显示的措词,添加为
value
。
注意-ATT的建议文字
- 为了根据您的个人喜好为您提供内容,该应用需要您的许可
- 为了向您提供合适的个性化内容,该应用需要访问您的设备ID
下表中列出了ATT弹出窗口中可能的用户操作和结果(基于开发人员在waitForATTUserAuthorization方法中设置的计时器)。
注意 :计时器到期后,无论是否收集IDFA,都会启动AppsFlyer SDK。
用户操作 | 结果 |
---|---|
在计时截止之前授权IDFA收集 |
收集IDFA |
在计时截止之前退出IDFA收集 |
不收集IDFA |
如果将弹窗留在后台不处理的话 |
直到用户将其返回到前台计时器都会暂停 |
将弹窗留在前端不处理,计时器结束后选择加入 |
收集IDFA |
将弹窗留在前端不处理,计时器结束后退出 |
不收集IDFA |
儿童应用
为了使该应用在“ App Store儿童”类别中可用,Apple要求您不要“将个人身份信息或设备信息传输给第三方”。为此,您必须明确禁用AdSupport和iAD框架。
要禁用广告框架:
[AppsFlyerLib shared].disableCollectASA = YES [AppsFlyerLib shared].disableAdvertisingIdentifier = YES;
AppsFlyerLib.shared().disableCollectASA = true AppsFlyerLib.shared().disableAdvertisingIdentifier = true
停止合作伙伴获取数据
在某些情况下,广告主可能希望停止与媒体渠道/合作伙伴共享特定用户的用户级数据。其原因包括:
- 隐私政策,例如CCPA或GDPR
- 用户选择退出机制
- 与某些合作伙伴(媒体渠道,第三方)的竞争
AppsFlyer提供了两种API方法来停止与某些或所有合作伙伴共享数据:
- setSharingFilter : 由广告商使用,以防止与 一些 (一个或多个)平台/集成合作伙伴 共享数据。
- setSharingFilterForAllPartners : 由广告主使用,以停止与 全部 广告平台/合作伙伴共享数据。
SDK V5.4.1+版本会支持这些方法。
每次SDK初始化 ,都必须调用过滤方法 ,这会影响全部会话。如果需要时间确定是否需要设置sharing filters,请延迟SDK初始化 。
在第一个 start调用之前激活该方法时:
- 当用户来自于SRN平台时 会被归因为自然安装用户,并且他们的数据不会回传给所对接的合作伙伴。
- 当用户来自于用追踪链接追踪的ad network时 (非SRN)在AppsFlyer中正确归因,但不会通过APIs,原始数据报告或者任何其他方法回传给ad network。
当前,无法使用这些方法过滤卸载数据。然而,你可以根据合伙伙伴的设置页面来停止向其发送卸载事件。
continueUserActivity
描述 |
从iOS 9及更高版本的Universal Link打开应用程序时调用onAppOpenAttribution 。 |
方法签名 |
|
用法示例 |
|
currencyCode
描述 |
为带有收入的event设置currency。接受ISO currency codes。 |
方法签名 |
|
用法示例 |
|
anonymizeUser
描述 |
匿名化用户的安装、事件和会话。有关更多信息,请参见匿名化用户数据 。 |
方法签名 |
|
用法示例 |
|
disableCollectASA
描述 |
从SDK版本4.8.11开始,AppsFlyer SDK动态加载Apple iAd.framework。在App中需要此框架去记录并且衡量Apple Search Ads的广告表现。如果您不希望AppsFlyer动态加载该框架,请设置此属性为true。 |
方法签名 |
|
用法示例 |
|
handleOpenUrl
描述 |
使用URI scheme的深层链接打开应用程序时,此方法将URI scheme报告给AppsFlyer SDK。此方法放置在AppDelegate中。 |
方法签名 |
|
用法示例 |
|
handlePushNotification
描述 |
测量并从推送通知活动中获取数据。有关更多信息,请参阅测量推送通知 。 |
方法签名 |
|
用法示例 |
|
isDebug
描述 |
在 Xcode console中展示AppsFlyer SDK日志。 调试应仅限于开发阶段。在启用调试的情况下,请勿将应用程序分发到 App Store。这会带来重大的安全和隐私风险。 |
方法签名 |
|
用法示例 |
|
isStopped
描述 |
关闭所有SDK功能。有关更多信息,请参阅用户隐私退出 。 |
方法签名 |
|
用法示例 |
|
onAppOpenAttribution
描述 |
通过深度链接打开应用时获取深度链接数据。 |
方法签名 |
|
用法示例 |
|
onAppOpenAttributionFailure
描述 |
处理获取深度链接数据时的报错。 |
方法签名 |
|
用法示例 |
|
onConversionDataSuccess
描述 |
安装后获取转化数据。对于延迟深度链接很有用。 注意: 从SDK 5.0版本开始,获取归因转化数据的方法名称更改为 |
方法签名 |
|
用法示例 |
|
onConversionDataFail
描述 |
无法获取安装转化数据时处理错误。 |
方法签名 |
|
用法示例 |
|
didResolveDeepLink
描述 |
打开应用后,立即将安装和未安装应用的移动用户发送到特定的应用内活动。了解更多 |
方法签名 |
|
performOnAppAttribution
描述 |
允许开发人员使用特定的链接(URI或URL)手动重新触发onAppOpenAttribution, 而不记录新的再互动 。如果应用程序需要基于给定的链接将用户跳转或者在应用停留在前台/打开时 解析AppsFlyer短链接 则可能需要此方法。可能需要此方法是因为仅当使用深度链接 打开应用程序 ,才会调用常规的onAppOpenAttribution回调。 |
方法签名 |
|
用法示例 |
|
registerUninstall
描述 |
监测卸载。请查阅 IOS卸载衡量。 |
方法签名 |
|
用法示例 |
|
resolveDeepLinkURLs
描述 |
解决点击域名中的OneLink。有关更多信息,请参见深度链接URL包装解析 。 |
方法签名 |
|
用法示例 |
|
setAdditionalData
描述 |
添加要发送到外部合作伙伴平台的其他数据。 |
方法签名 |
|
用法示例 |
请参阅设置其他自定义数据 。 |
setAppInviteOneLink
描述 |
设置用于为用户邀请创建自定义归因链接的OneLink模板ID。 |
方法签名 |
|
用法示例 |
请参阅将 OneLink用于用户邀请归因 。 |
setAppleAppID
描述 |
设置你的 app ID (itunes ID) 以便SDK可以将数据发送到正确app的dashboard。当您 初始化 SDK时启用它。 |
方法签名 |
|
用法示例 |
|
appsFlyerDevKey
描述 |
请设置AppsFlyer dev key以便SDK可以将数据发送到正确app的dashboard。当您 初始化 SDK时启用它。 要了解如何获取您的dev key,请查阅 这里。 |
方法签名 |
|
用法示例 |
|
设置客户用户 ID
描述 |
设置客户用户标识 (Customer User ID)。有关更多信息,请参见设置Customer User ID 。 |
方法签名 |
|
用法示例 |
setSharingFilter
描述 |
广告客户使用它来设置 一些 (一个或多个)网络/集成合作伙伴来获取 排除 数据。 |
方法签名 |
|
用法示例 |
|
setSharingFilterForAllPartners
描述 |
被广告主用来排除所有 平台/对接合作伙伴 获得数据。 |
方法签名 |
|
用法示例 |
|
setShouldCollectDeviceName
描述 |
SDK是否应收集设备名称。默认为false。 |
方法签名 |
|
用法示例 |
|
setUseUninstallSandbox
描述 |
要测试仍在开发中(尚未在Apple App Store里发布)App的卸载,请将此属性设置为true |
方法签名 |
|
用法示例 |
|
startWithCompletionHandler
描述 |
检查start 是否成功。您可以加入您自己的逻辑来处理SDK初始化的成功或失败。 |
方法签名 |
|
用法示例 |
logEvent
描述 |
将应用内事件发给AppsFlyer。有关更多信息,请参阅记录应用内事件 。 |
方法签名 |
|
用法示例 |
|
validateAndLogInAppPurchase
描述 |
设置AppsFlyer dev key以便SDK可以将数据发送到正确app的dashboard。要了解如何获取您的dev key,请查阅 这里。当您 初始化 SDK时启用它。 |
方法签名 |
|
用法示例 |
请查阅应用内购买验证。 |
disableAdvertisingIdentifier
描述 |
从SDK版本4.8.11开始,AppsFlyer SDK可动态加载Apple的adSupport.framework。需要此框架来收集IDFA以进行归因。如果您不希望AppsFlyer动态加载该框架,请设置此属性为true。 |
方法签名 |
|
用法示例 |
[AppsFlyerLib shared].disableAdvertiserIdentifier=YES; [AppsFlyerLib shared].disableAdvertiserIdentifier== true |
waitForATTUserAuthorization
描述 |
如果您要在访问与应用程序相关的数据以记录用户或设备(例如IDFA)之前要通过弹出窗口请求用户授权,则使用此选项。如果用户选择同意,则IDFA将可被SDK收集。超时间隔为用户提供了对于收集IDFA选择opt-in的时间。到时间后,将不会收集IDFA。 |
方法签名 |
|
用法示例 |
|
start
描述 |
调用此API后SDK将初始化,session(会话)将会立刻发送,并且所有的后台调换前台也会被记录一个session(会话)。 |
方法签名 |
|
用法示例 |
|
logLocation
描述 |
手动记录用户的 位置。 |
方法签名 |
|
用法示例 |
|
appendParametersToDeepLinkingURL
描述 |
使应用程序所有者可以使用通用链接进行深层链接(不使用OneLink),以将会话通过一个与他们app相关联的domain来归因。在调用start之前先调用此方法。 该方法需要:
|
方法签名 |
|
用法示例 |
|
addPushNotificationDeepLinkPath
描述 |
设置SDK如何从推送通知的payload中提取深度链接值。 |
方法签名 |
|
用法示例 |
此调用方法可匹配以下调用方法:
|
disableSKAdNetwork
描述 |
允许您禁用SKAdNetwork归因。设置为true 以禁用。 |
方法签名 |
|
用法示例 |
|
评论
请登录写评论。