iOS Unified Deep Linking
概要:Unified Deep Linking(UDL)により、アプリ起動時に新規および既存ユーザーを特定のアプリ内アクティビティ(例えば、アプリ内の特定のページなど)に誘導することができます。
UDLのプライバシー保護
For new users, the UDL method only returns parameters relevant to deferred deep linking:
deep_link_value
anddeep_link_sub1-10
. If you try to get any other parameters (media_source
,campaign
,af_sub1-5
など)、null を返します。
フロー
計測フローは次のとおりです。
- ユーザーがOneLinkのリンクをクリックします。
- ユーザーがアプリをインストールしている場合は、ユニバーサルリンクまたはURIスキームでアプリを開きます。
- ユーザーがアプリをインストールしていない場合は、アプリストアにリダイレクトされ、ダウンロード後、アプリを開きます。
- アプリ起動がAppsFlyer SDKをトリガーします。
- AppsFlyer SDKはUDL APIを実行します。
- UDL APIはOneLinkデータをAppsFlyerサーバーから取得します。
- The UDL API calls back the
didResolveDeepLink()
in theDeepLinkDelegate
. - The
didResolveDeepLink()
method gets aDeepLinkResult
object. - The
DeepLinkResult
object includes:- ステータス (Found/Not found/Failure)
- A
DeepLink
object that carries thedeep_link_value
anddeep_link_sub1-10
parameters that the developer uses to route the user to a specific in-app activity, which is the main goal of OneLink.
計画
- UDL には、AppsFlyer iOS SDK V6.1以降が必要です。
OneLinkを設定する際は、マーケティング担当者はこのパラメーターをリンクを作成するために使用し、ディベロッパーは、受け取った値をもとにアプリの動作をカスタマイズします。アプリ内でのルーティングやリンク先でのデータのパーソナライズなど、アプリ内でパラメータが正しく処理されるように実装するのはディベロッパーの責任です。
OneLinkの計画方法:
- ユーザーがURLをクリックしたときに、どのような動作が発生し、どのような体験をするのかをマーケティング担当者からヒアリングしてください。
- Based on the desired behavior, plan the
deep_link_value
and other parameters that are needed to give the user the desired personal experience.- The
deep_link_value
is set by the marketer in the URL and used by the developer to redirect the user to a specific place inside the app. For example, if you have a fruit store and want to direct users to apples, the value ofdeep_link_value
can beapples
. - The
deep_link_sub1-10
parameters can also be added to the URL to help personalize the user experience. For example, to give a 10% discount, the value ofdeep_link_sub1
can be10
.
- The
実装
Let's save you some time >>
Set Deep Linking with our SDK integration wizard
UDL APIを選択したパラメーターと値に基づいて実装してください。
- Assign the
AppDelegate
usingself
toAppsFlyerLib.shared().deepLinkDelegate
. - アプリケーションの関数を実装して、以下を許可してください:
- ユニバーサルリンクが以下に対応:
continue
. - URIが以下に対応:
handleOpen
.
- ユニバーサルリンクが以下に対応:
- Create
DeepLinkDelegate
as an extension ofAppDelegate
. - Add
application
functions to support Universal Links and URI schemes. - In
DeepLinkDelegate
, make sure you override the callback function,didResolveDeepLink()
.
didResolveDeepLink()
accepts aDeepLinkResult
object as an argument. - Use
DeepLinkResult.status
to query whether the deep linking match is found. - For when the status is an error, call
DeepLinkResult.error
and run your error flow. - For when the status is found, use
DeepLinkResult.deepLink
to retrieve theDeepLink
object.
TheDeepLink
object contains the deep linking information arranged in public variables to retrieve the values from well-known OneLink keys, for example,DeepLink.deeplinkValue
fordeep_link_value
. - Use
deepLinkObj.clickEvent["deep_link_sub1"]
to retrievedeep_link_sub1
. Do the same fordeep_link_sub2-10
parameters, changing the string value as required. - Once
deep_link_value
anddeep_link_sub1-10
are retrieved, pass them to an in-app router and use them to personalize the user experience.
Supporting legacy OneLink links
従来のOneLinkリンクは、Unified Deep Linkingに推奨されるパラメーターを含まないリンクです: deep_link_value
and deep_link_sub1-10
.
Usually these are links that already exist in the field when migrating from legacy methods to UDL.
News users using legacy links are handled by onConversionDataSuccess
拡張ディファードディープリンクのコンテキストで
UDL は、既存のユーザーのディープリンクを処理します。UDLのコールバックにサポートを追加することをお勧めします didResolveDeepLink
for legacy parameters.
Swift code example
Code example
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Replace 'appleAppID' and 'appsFlyerDevKey' with your Apple App ID (eg 69999999, without id prefix) and DevKey
// The App ID and the DevKey must be set prior to the calling of the deepLinkDelegate
AppsFlyerLib.shared().appleAppID = appleAppID
AppsFlyerLib.shared().appsFlyerDevKey = appsFlyerDevKey
...
AppsFlyerLib.shared().deepLinkDelegate = self
...
}
// 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 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
}
extension AppDelegate: DeepLinkDelegate {
func didResolveDeepLink(_ result: DeepLinkResult) {
var fruitNameStr: String?
switch result.status {
case .notFound:
NSLog("[AFSDK] Deep link not found")
return
case .failure:
print("Error %@", result.error!)
return
case .found:
NSLog("[AFSDK] Deep link found")
}
guard let deepLinkObj:DeepLink = result.deepLink else {
NSLog("[AFSDK] Could not extract deep link object")
return
}
if deepLinkObj.clickEvent.keys.contains("deep_link_sub2") {
let ReferrerId:String = deepLinkObj.clickEvent["deep_link_sub2"] as! String
NSLog("[AFSDK] AppsFlyer: Referrer ID: \(ReferrerId)")
} else {
NSLog("[AFSDK] Could not extract referrerId")
}
let deepLinkStr:String = deepLinkObj.toString()
NSLog("[AFSDK] DeepLink data is: \(deepLinkStr)")
if( deepLinkObj.isDeferred == true) {
NSLog("[AFSDK] This is a deferred deep link")
}
else {
NSLog("[AFSDK] This is a direct deep link")
}
fruitNameStr = deepLinkObj.deeplinkValue
walkToSceneWithParams(fruitName: fruitNameStr!, deepLinkData: deepLinkObj.clickEvent)
}
}
// User logic
fileprivate func walkToSceneWithParams(deepLinkObj: DeepLink) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true, completion: nil)
guard let fruitNameStr = deepLinkObj.clickEvent["deep_link_value"] as? String else {
print("Could not extract query params from link")
return
}
let destVC = fruitNameStr + "_vc"
if let newVC = storyBoard.instantiateVC(withIdentifier: destVC) {
print("AppsFlyer routing to section: \(destVC)")
newVC.deepLinkData = deepLinkObj
UIApplication.shared.windows.first?.rootViewController?.present(newVC, animated: true, completion: nil)
} else {
print("AppsFlyer: could not find section: \(destVC)")
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Set isDebug to true to see AppsFlyer debug logs
[AppsFlyerLib shared].isDebug = YES;
// Replace 'appsFlyerDevKey', `appleAppID` with your DevKey, Apple App ID
[AppsFlyerLib shared].appsFlyerDevKey = appsFlyerDevKey;
[AppsFlyerLib shared].appleAppID = appleAppID;
[AppsFlyerLib shared].deepLinkDelegate = self;
return YES;
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
[[AppsFlyerLib shared] continueUserActivity:userActivity restorationHandler:nil];
return YES;
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
[[AppsFlyerLib shared] handleOpenUrl:url options:options];
return YES;
}
#pragma mark - DeepLinkDelegate
- (void)didResolveDeepLink:(AppsFlyerDeepLinkResult *)result {
NSString *fruitNameStr;
NSLog(@"[AFSDK] Deep link lowkehy");
switch (result.status) {
case AFSDKDeepLinkResultStatusNotFound:
NSLog(@"[AFSDK] Deep link not found");
return;
case AFSDKDeepLinkResultStatusFailure:
NSLog(@"Error %@", result.error);
return;
case AFSDKDeepLinkResultStatusFound:
NSLog(@"[AFSDK] Deep link found");
break;
}
AppsFlyerDeepLink *deepLinkObj = result.deepLink;
if ([deepLinkObj.clickEvent.allKeys containsObject:@"deep_link_sub2"]) {
NSString *referrerId = deepLinkObj.clickEvent[@"deep_link_sub2"];
NSLog(@"[AFSDK] AppsFlyer: Referrer ID: %@", referrerId);
} else {
NSLog(@"[AFSDK] Could not extract referrerId");
}
NSString *deepLinkStr = [deepLinkObj toString];
NSLog(@"[AFSDK] DeepLink data is: %@", deepLinkStr);
if (deepLinkObj.isDeferred) {
NSLog(@"[AFSDK] This is a deferred deep link");
if (self.deferredDeepLinkProcessedFlag) {
NSLog(@"Deferred deep link was already processed by GCD. This iteration can be skipped.");
self.deferredDeepLinkProcessedFlag = NO;
return;
}
} else {
NSLog(@"[AFSDK] This is a direct deep link");
}
fruitNameStr = deepLinkObj.deeplinkValue;
// If deep_link_value doesn't exist
if (!fruitNameStr || [fruitNameStr isEqualToString:@""]) {
// Check if fruit_name exists
id fruitNameValue = deepLinkObj.clickEvent[@"fruit_name"];
if ([fruitNameValue isKindOfClass:[NSString class]]) {
fruitNameStr = (NSString *)fruitNameValue;
} else {
NSLog(@"[AFSDK] Could not extract deep_link_value or fruit_name from deep link object with unified deep linking");
return;
}
}
// This marks to GCD that UDL already processed this deep link.
// It is marked to both DL and DDL, but GCD is relevant only for DDL
self.deferredDeepLinkProcessedFlag = YES;
[self walkToSceneWithParams:fruitNameStr deepLinkData:deepLinkObj.clickEvent];
}
- (void)walkToSceneWithParams:(NSString *)fruitName deepLinkData:(NSDictionary *)deepLinkData {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
[[UIApplication sharedApplication].windows.firstObject.rootViewController dismissViewControllerAnimated:YES completion:nil];
NSString *destVC = [fruitName stringByAppendingString:@"_vc"];
DLViewController *newVC = [storyboard instantiateViewControllerWithIdentifier:destVC];
NSLog(@"[AFSDK] AppsFlyer routing to section: %@", destVC);
newVC.deepLinkData = deepLinkData;
[[UIApplication sharedApplication].windows.firstObject.rootViewController presentViewController:newVC animated:YES completion:nil];
}
⇲ Github links: Swift
⇲ Github links: Objective-C
Deferred Deep Linking after network consent
In some cases the application might require consent from the user in order to connect to the network, in a dialog similar to this one:

In order to support deferred deep linking once the network consent is given we recommend:
- Implement eDDL to allow UDL to handle the deferred deep linking
ディファードディプリンクのテスト
Prerequisites
- UDL実装を完了してください。
- テストデバイスの登録
- アプリでデバッグモードを有効にしてください。
- 端末にアプリがインストールされていないことを確認してください。
- マーケティング担当者もしくはAppsFlyer管理画面からOneLinkテンプレートを取得してください。
- リンクはこのようになります:
https://onelink-basic-app.onelink.me/H5hv
. - This example uses the OneLink subdomain
onelink-basic-app.onelink.me
and the OneLink template IDH5hv
.
- リンクはこのようになります:
The test link
既存のOneLinkリンクを使用することも、テスト用にマーケティング担当者に新しいリンクを作成してもらうこともできます。OneLinkのURLは、ショートリンクとロングリンクのどちらでも使用できます。
既存のリンクに一時的にパラメータを追加する
- リンクのドメインとOneLinkテンプレートのみを使用してください。
例:https://onelink-basic-app.onelink.me/H5hv
. - Add OneLink parameters
deep_link_value
anddeep_link_sub1-10
アプリケーションで期待どおり。パラメータは、クエリパラメータとして追加する必要があります。
例:https://onelink-basic-app.onelink.me/H5hv?pid=my_media_source&deep_link_value=apples&deep_link_sub1=23
Perform the test
- 端末でリンクをクリックします。
- AppsFlyer管理画面で設定されたOneLinkの設定内容を基に、App StoreまたはWebサイトのいずれかにリダイレクトします。
- アプリをインストールします。
重要
- アプリがまだ開発中で、ストアにアップロードされていない場合、このような画像が表示されます:
- Xcodeからアプリをインストールします。
- アプリがまだ開発中で、ストアにアップロードされていない場合、このような画像が表示されます:
- UDL detects the deferred deep linking, matches the install to the click, and retrieves the OneLink parameters to
didResolveDeepLink
callback.
Expected logs results
📘 次のログは、デバッグモードが有効になっている場合にのみ使用できます。
- SDKが初期化された場合:
[AppsFlyerSDK] [com.apple.main-thread] AppsFlyer SDK version 6.6.0 started build
- UDL APIの開始:
D/AppsFlyer_6.9.0: [DDL] start
- UDLがAppsFlyerにクエリを送信し、このインストールとの一致を問い合わせる:
[AppsFlyerSDK] [com.appsflyer.serial] [DDL] URL: https://dlsdk.appsflyer.com/v1.0/ios/id1512793879?sdk_version=6.6&af_sig=efcecc2bc95a0862ceaa7b62fa8e98ae1e3e022XXXXXXXXXXXXXXXX
- UDL は応答を受け取り、呼び出します
didResolveDeepLink
コールバックstatus=FOUND
およびOneLinkリンクデータ:[AppsFlyerSDK] [com.appsflyer.serial] [DDL] Calling didResolveDeepLink with: {"af_sub4":"","click_http_referrer":"","af_sub1":"","click_event":{"af_sub4":"","click_http_referrer":"","af_sub1":"","af_sub3":"","deep_link_value":"peaches","campaign":"","match_type":"probabilistic","af_sub5":"","campaign_id":"","media_source":"","deep_link_sub1":"23","af_sub2":""},"af_sub3":"","deep_link_value":"peaches","campaign":"","match_type":"probabilistic","af_sub5":"","media_source":"","campaign_id":"","af_sub2":""}
ディープリンクのテスト (Universal Links)
Prerequisites
- UDL実装を完了してください。
- テストデバイスの登録
- アプリでデバッグモードを有効にしてください。
- アプリがすでにデバイスにインストールされていることを確認してください。
- マーケティング担当者もしくはAppsFlyer管理画面からOneLinkテンプレートを取得してください。
- リンクはこのようになります:
https://onelink-basic-app.onelink.me/H5hv
. - This example uses the OneLink subdomain
onelink-basic-app.onelink.me
and the OneLink template IDH5hv
- リンクはこのようになります:
- Configure Universal Links.
Create the test link
ディファードディープリンクと同じ方法を使用します。
Perform the test
- 端末でリンクをクリックします。
- UDL detects the Universal Link and retrieves the OneLink parameters to
didResolveDeepLink
callback.
Expected logs results
📘 次のログは、デバッグモードが有効になっている場合にのみ使用できます。
- リンクがOneLinkショートリンクの場合(例:https://onelink-basic-app.onelink.me/H5hv/apples)
[AppsFlyerSDK] [com.apple.main-thread] NSUserActivity `webpageURL`: https://onelink-basic-app.onelink.me/H5hv/apples [AppsFlyerSDK] [com.appsflyer.serial] UniversalLink/Deeplink found: https://onelink-basic-app.onelink.me/H5hv/apples [AppsFlyerSDK] [com.appsflyer.serial] Shortlink found. Executing: https://onelink.appsflyer.com/shortlink-sdk/v2/H5hv?id=apples ... [AppsFlyerSDK] [com.appsflyer.serial] [Shortlink] OneLink:{ c = test1; campaign = test1; "deep_link_sub1" = 23; "deep_link_value" = peaches; "is_retargeting" = true; "media_source" = SMS; pid = SMS; }
- UDL 呼び出し
didResolveDeepLink
コールバックstatus=FOUND
およびOneLinkリンクデータ:[AppsFlyerSDK] [com.appsflyer.serial] [DDL] Calling didResolveDeepLink with: {"af_sub4":null,"click_http_referrer":null,"af_sub1":null,"click_event":{"campaign":"test1","deep_link_sub1":"23","deep_link_value":"peaches","media_source":"SMS"},"af_sub3":null,"deep_link_value":"peaches","campaign":"test1","match_type":null,"af_sub5":null,"media_source":"SMS","campaign_id":null,"af_sub2":null}
更新済 約1ヶ月前