概要:本文说明了现有AppsFlyer iOS SDK/iOS SDK V6嵌套对接的更新方式。
iOS SDK V6简介
本文中所提供的信息适用于SDK V6。
AppsFlyer iOS SDK V6具有以下特点:
- 帮助应用所有者和开发人员在iOS 14发布前做好应对准备。
- 让您在收集IDFA时能请求用户授权。
- 提供iOS用户的归因和事件上报功能。
- 对早前版本中的API方法进行了重大更新。
如需全面了解有关SDK V6的详细信息,或需要在从未安装过AppsFlyer SDK的应用中接入SDK V6,请参考我们为营销人员提供的iOS SDK对接指南。
更新到iOS SDK V6
请按以下流程(第1-5步)将您的iOS SDK SDK更新到V6。
1. 更新SDK版本
下载SDK V6并将其添加到您的Xcode中。
2. 接入SDK V6
请在SDK初始化部分添加以下代码:
在 AppDelegate.h 中完成以下操作:
#import "AppDelegate.h"
#import <AppsFlyerLib/AppsFlyerLib.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <UserNotifications/UserNotifications.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 1 - Get AppsFlyer preferences from .plist file
NSString *path = [[NSBundle mainBundle] pathForResource:@"afdevkey_donotpush" ofType:@".plist"];
NSDictionary* properties = [NSDictionary dictionaryWithContentsOfFile:path];
if (properties == nil || path == nil) {
[NSException raise:@"Error" format:@"Cannot find .plist file"];
}
NSString* appsFlyerDevKey = [properties objectForKey:@"appsFlyerDevKey"];
NSString* appleAppID = [properties objectForKey:@"appleAppID"];
if (appsFlyerDevKey == nil || appleAppID == nil) {
[NSException raise:@"Error" format:@"Cannot find appsFlyerDevKey or appleAppID"];
}
// 2 - Replace 'appsFlyerDevKey', `appleAppID` with your DevKey, Apple App ID
[[AppsFlyerLib shared] setAppsFlyerDevKey:appsFlyerDevKey];
[[AppsFlyerLib shared] setAppleAppID:appleAppID];
[AppsFlyerLib shared].delegate = self;
// Set isDebug to true to see AppsFlyer debug logs
[AppsFlyerLib shared].isDebug = true;
if (@available(iOS 10, *)) {
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 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
在 AppDelegate.swift 中添加以下代码:
import UIKit
import AppTrackingTransparency
import AppsFlyerLib
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 1 - Get AppsFlyer preferences from .plist file
guard let propertiesPath = Bundle.main.path(forResource: "afdevkey_donotpush", ofType: "plist"),
let properties = NSDictionary(contentsOfFile: propertiesPath) as? [String:String] else {
fatalError("Cannot find `afdevkey_donotpush`")
}
guard let appsFlyerDevKey = properties["appsFlyerDevKey"],
let appleAppID = properties["appleAppID"] else {
fatalError("Cannot find `appsFlyerDevKey` or `appleAppID` key")
}
// 2 - Replace 'appsFlyerDevKey', `appleAppID` with your DevKey, Apple App ID
AppsFlyerLib.shared().appsFlyerDevKey = appsFlyerDevKey
AppsFlyerLib.shared().appleAppID = appleAppID
AppsFlyerLib.shared().delegate = self
// Set isDebug to true to see AppsFlyer debug logs
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 {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.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 { // this line for Swift < 4.2
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
return true
}
// Open Deeplinks
// Open URI-scheme for iOS 8 and below
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
AppsFlyerLib.shared().handleOpen(url, sourceApplication: sourceApplication, withAnnotation: annotation)
return true
}
// Open URI-scheme for iOS 9 and above
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
AppsFlyerLib.shared().handleOpen(url, options: options)
return true
}
// Report Push Notification attribution data for re-engagements
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
AppsFlyerLib.shared().handlePushNotification(userInfo)
}
}
extension AppDelegate: AppsFlyerLibDelegate {
// Handle Organic/Non-organic installation
func onConversionDataSuccess(_ data: [AnyHashable: Any]) {
print("onConversionDataSuccess data:")
for (key, value) in data {
print(key, ":", value)
}
if let status = data["af_status"] as? String {
if (status == "Non-organic") {
if let sourceID = data["media_source"],
let campaign = data["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 = data["is_first_launch"] as? Bool,
is_first_launch {
print("First Launch")
} else {
print("Not First Launch")
}
}
}
func onConversionDataFail(_ error: Error) {
print("\(error)")
}
// Handle Deeplink
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. 支持SKAdNetwork归因
SKAdNetwork是iOS中用来验证非自然激活的一种方案。此方案下的应用激活验证流程涉及到流量方应用(source app)和广告主应用(advertised app)。
在广告平台上投放(带有广告平台签名)的广告会展示在流量方应用(source app)中。如需让您的应用展示广告,无法通过AppsFlyer SDK完成相关配置,您必须根据iOS的说明进行操作。
如需配置您要推广的应用,请使用AppsFlyer的SKAdNetwork解决方案。该方案通过SKAdNetwork为广告主和广告平台提供LTV维度的分析数据、报告及回传,并能同时保障用户隐私。用户首次启动相关应用时,AppsFlyer平台会根据广告主的指定配置,让SDK设置SKAdNetwork转化值。
如需使用SKAdNetwork解决方案,请按以下方式操作:
- 开发人员无需操作。
-
AppsFlyer SDK会自动调用必要的SKAdNetwork API,即
registerAppForAdNetworkAttribution()
和updateConversionValue()
。开发人员请勿再单独调用。 - 请勿允许其他SDK调用SKAdNet API,否则可能会导致iOS向AppsFlyer发送回传时产生延迟,并使转化值发生变化,使得SKAdNetwork面板无法根据广告主的配置来呈现用户质量评估数据。
- 广告主需要在其AppsFlyer面板中配置SKAdNetwork衡量方案。
开发人员和市场人员都无需在应用商店中再完成其他操作或注册流程。
4. 更改API
AppsFlyer iOS SDK V6更改了部分API的名称。请根据下表信息,对早前版本SDK中相关的API名称进行更新。
V6之前的API名称 | 当前的API名称(V6和更高版本) |
---|---|
AppsFlyerTracker | AppsFlyerLib |
disableIAdTracking | disableCollectASA |
trackAppLaunchWithCompletionHandler |
startWithCompletionHandler |
trackLocation |
logLocation |
trackAppLaunch |
start |
trackEvent |
logEvent |
disableAppleAdSupportTracking |
disableAdvertisingIdentifier |
validateAndTrackInAppPurchase |
validateAndLogInAppPurchase |
isStopTracking |
isStopped |
deviceTrackingDisabled/deviceLoggingDisabled |
anonymizeUser |
sharedTracker (Objective C) | shared |
5. 接入推送通知
如果推送通知已对接完毕,您还需要完成以下操作:
请根据推送通知说明文档完成相关操作,确保您使用handlePushNotificationData方法接入推送通知。
插件
可用的V6插件包括以下几种:
Unity
AppsFlyer Unity V6 plugin插件能够帮助应用所有者和开发人员为应对iOS 14做好准备,针对使用Unity平台开发的安卓和iOS应用,提供移动端用户的归因和事件上报。该插件在功能上等同于AppsFlyer iOS和Android SDK。
如需对早前版本的插件进行更新,请根据您的实际情况参考以下指南,以便顺利更新到V6版本的Unity:
- 从V4版本的Unity插件更新(需要移除旧版插件)
- 从V5版本的Unity插件更新(需要更新Unity package)
React Native
AppsFlyer React Native插件能够帮助应用所有者和开发人员为应对iOS 14做好准备,保障安卓和iOS用户的归因和事件上报。该插件在功能上等同于AppsFlyer iOS和Android SDK。
如需对早前版本的插件进行更新,请按以下方式操作:
- 移除旧版插件,并按我们在GitHub指南中提供的说明将其替换为新版本。
- 在集成代码中更改相关API的名称或将其删除。
Segment
AppsFlyer Segment插件能够帮助应用所有者和开发人员为应对iOS 14做好准备,保障安卓和iOS用户的归因和事件上报。该插件在功能上等同于AppsFlyer iOS和Android SDK。
如需对早前版本的插件进行更新,请移除旧版插件,并按我们在GitHub指南中提供的说明将其替换为新版本。
Cordova
AppsFlyer Cordova插件能够帮助应用所有者和开发人员为应对iOS 14做好准备,保障安卓和iOS用户的归因和事件上报。该插件在功能上等同于AppsFlyer iOS和Android SDK。
如需对早前版本的插件进行更新,请移除旧版插件,并按我们在GitHub指南中提供的说明将其替换为新版本。
Flutter
AppsFlyer Flutter插件能够帮助应用所有者和开发人员为应对iOS 14做好准备,保障安卓和iOS用户的归因和事件上报。该插件在功能上等同于AppsFlyer iOS和Android SDK。
如需对早前版本的插件进行更新,请移除旧版插件,并将V6版插件添加到pubspec.yaml
。请按照pub.dev指南中的说明完成相关操作。
Adobe AIR
AppsFlyer Adobe AIR插件能够帮助应用所有者和开发人员为应对iOS 14做好准备,保障安卓和iOS用户的归因和事件上报。该插件在功能上等同于AppsFlyer iOS和Android SDK。
如需对早前版本的插件进行更新,请移除旧版插件,并按我们在GitHub指南中提供的说明将其替换为新版本。