前提条件
この統合を進める前に、 Singular SDK の統合:計画と前提条件 の手順を完了してください。
重要: これらの前提条件の手順は、Singular SDK の統合に必須です。
iOS 固有のセットアップ
SDK を初期化する前に、Xcode プロジェクトで以下が設定されていることを確認してください。これらのいずれかが欠けていることが、SDK の無音障害の一般的な原因です。
Info.plist のエントリ:
-
NSUserTrackingUsageDescription— アプリがトラッキングを要求する理由を説明する、ユーザー向けの文字列です。App Tracking Transparency (ATT) プロンプトを表示するか、IDFA を読み取る場合は Apple により必須となります。Singular SDK は ATT を自動的に尊重します。このキーがなくても SDK は動作しますが、iOS 14.5 以降では IDFA にアクセスできません。 -
URL Types と
CFBundleURLSchemes— ディープリンク戦略でカスタム URI スキーム(例:myapp://)を使用する場合に必要です。HTTPS 経由の Universal Links / Singular Links には不要です。
エンタイトルメント(Signing & Capabilities):
-
Associated Domains
— Singular のブランドドメインごとに、
applinks:yourcompany.sng.linkの形式でエントリを追加します。Universal Link / Singular Link のアトリビューションに必須です。この Singular ホストドメインは、Apple がインストール時にダウンロードするapple-app-site-association(AASA) JSON ファイルをホストします。AASA ファイルは、Singular プラットフォームでアプリのリンクが作成された際に生成および更新されます。 - Push Notifications — アンインストール トラッキングおよびプッシュ アトリビューションによる再エンゲージメントに必須です。Push Notifications のサポートおよびアンインストール トラッキングに関する記事を参照してください。
必須のシステムフレームワーク(手動統合の場合のみ — CocoaPods および SwiftPM は自動的にリンクします):
-
StoreKit.framework— IAP および SKAdNetwork。 -
AdServices.framework— Apple Search Ads アトリビューション トークン(iOS 14.3 以降)。 -
AppTrackingTransparency.framework— ATT プロンプトと認可ステータス(iOS 14.5 以降)。 -
UserNotifications.framework— プッシュ通知。 -
WebKit.framework— Singular の WKWebView JS ブリッジを使用する場合のみ必要です。
インストール
お好みのインストール方法を選択してください。ほとんどのプロジェクトでは CocoaPods を推奨します。
クイック判断:
- すでに CocoaPods を使用していますか? 方法 1 を使用
- SPM のみのプロジェクトですか? 方法 2 を使用
- パッケージマネージャーを使用していませんか? 方法 3 を使用
インストール方法
方法 1:CocoaPods(推奨)
要件:
- CocoaPods がインストールされていること( インストールガイド )
- プロジェクトディレクトリへのターミナルアクセス
インストール手順:
-
Podfile の初期化 (すでにある場合はスキップ):
cd /path/to/your/project pod init -
Singular SDK を追加 して Podfile に記述:
platform :ios, '12.0' target 'YourAppName' do use_frameworks! # Singular SDK pod 'Singular-SDK' end -
依存関係のインストール:
pod install -
ワークスペースを開く:
今後は、
.xcodeprojではなく.xcworkspaceを開いてください - Swift プロジェクトのみ: ブリッジングヘッダーを作成 (以下を参照)
方法 2:Swift Package Manager
インストール手順:
- Xcode で: File → Add Packages
-
リポジトリ URL を入力:
https://github.com/singular-labs/Singular-iOS-SDK - バージョンを選択して Add Package をクリック
-
必須フレームワークを追加:
Build Phases → Link Binary with Libraries に移動して、以下を追加:-
必須のライブラリをリンク:
Build Phases → Link Binary With Libraries に移動して、以下を追加:- Libsqlite3.0.tbd
- SystemConfiguration.framework
- Security.framework
- Libz.tbd
- AdSupport.framework
- WebKit.framework
- StoreKit.framework
- AdServices.framework(Optional としてマーク)
-
必須のライブラリをリンク:
- Swift プロジェクトのみ: ブリッジングヘッダーを作成 (以下を参照)
方法 3:フレームワークの手動インストール
使用する場合: CocoaPods または SPM が使用できない場合にのみ、この方法を使用してください。
フレームワークをダウンロード:
- Xcode 12 以降: .xcframework をダウンロード
- Xcode 11 以下: .framework をダウンロード
インストール手順:
- ダウンロードしたフレームワークを解凍
- Xcode で:プロジェクトを右クリック → Add Files To [Project]
- Create Groups を選択し、フレームワークフォルダーを追加
-
必須のライブラリをリンク:
Build Phases → Link Binary With Libraries に移動して、以下を追加:- Libsqlite3.0.tbd
- SystemConfiguration.framework
- Security.framework
- Libz.tbd
- AdSupport.framework
- WebKit.framework
- StoreKit.framework
- AdServices.framework(Optional としてマーク)
-
フレームワークの埋め込み:
General → Frameworks, Libraries, and Embedded Content に移動
Singular フレームワークを Embed & Sign に設定
Swift ブリッジングヘッダー
重要: CocoaPods または SPM を使用する Swift プロジェクトには必須です。
-
ヘッダーファイルを作成:
Xcode → File → New → File → Header File
名前をYourProjectName-Bridging-Header.hとする -
インポートを追加:
#import <Singular/Singular.h> -
ビルド設定でリンク:
Build Settings → Objective-C Bridging Header
次のように設定:YourProjectName/YourProjectName-Bridging-Header.h
SDK の設定と初期化
設定オブジェクトを作成し、アプリのエントリポイントで SDK を初期化します。
設定オブジェクトの作成
基本設定
SDK 認証情報とオプション機能を含む
SingularConfig
オブジェクトを作成します。この設定は、すべてのアプリアーキテクチャで共通です。
認証情報を取得: Singular プラットフォームの Developer Tools → SDK Integration で、SDK Key と SDK Secret を確認してください。
// MARK: - Singular Configuration
private func getConfig() -> SingularConfig? {
// Create config with your credentials
guard let config = SingularConfig(
apiKey: "YOUR_SDK_KEY",
andSecret: "YOUR_SDK_SECRET"
) else {
return nil
}
// OPTIONAL: Wait for ATT consent (if showing ATT prompt)
// Remove this line if NOT using App Tracking Transparency
config.waitForTrackingAuthorizationWithTimeoutInterval = 300
// OPTIONAL: Support custom ESP domains for deep links
config.espDomains = ["links.your-domain.com"]
// OPTIONAL: Handle deep links
config.singularLinksHandler = { params in
if let params = params {
self.handleDeeplink(params)
}
}
return config
}
// MARK: - OPTIONAL: Deep link handler implementation
private func handleDeeplink(_ params: SingularLinkParams) {
// Guard clause: Exit if no deep link provided
guard let deeplink = params.getDeepLink() else {
return
}
// Extract deep link parameters
let passthrough = params.getPassthrough()
let isDeferred = params.isDeferred()
let urlParams = params.getUrlParameters()
#if DEBUG
// Debug logging only - stripped from production builds
print("Singular Links Handler")
print("Singular deeplink received:", deeplink)
print("Singular passthrough received:", passthrough ?? "none")
print("Singular isDeferred received:", isDeferred ? "YES" : "NO")
print("Singular URL Params received:", urlParams ?? [:])
#endif
// TODO: Navigate to appropriate screen based on deep link
// Add deep link handling code here. Navigate to appropriate screen.
}
#pragma mark - Singular Configuration
- (SingularConfig *)getConfig {
// Create config with your credentials
SingularConfig *config = [[SingularConfig alloc]
initWithApiKey:@"YOUR_SDK_KEY"
andSecret:@"YOUR_SDK_SECRET"];
// OPTIONAL: Wait for ATT consent (if showing ATT prompt)
// Remove this line if NOT using App Tracking Transparency
config.waitForTrackingAuthorizationWithTimeoutInterval = 300;
// OPTIONAL: Support custom ESP domains for deep links
config.espDomains = @[@"links.your-domain.com"];
// OPTIONAL: Handle deep links
config.singularLinksHandler = ^(SingularLinkParams *params) {
[self handleDeeplink:params];
};
return config;
}
#pragma mark - OPTIONAL: Deep link handler implementation
- (void)handleDeeplink:(SingularLinkParams *)params {
// Guard clause: Exit if params is nil
if (!params) {
return;
}
// Guard clause: Exit if no deep link provided
NSString *deeplink = [params getDeepLink];
if (!deeplink) {
return;
}
// Extract deep link parameters
NSString *passthrough = [params getPassthrough];
BOOL isDeferred = [params isDeferred];
NSDictionary *urlParams = [params getUrlParameters];
#ifdef DEBUG
// Debug logging only - stripped from production builds
NSLog(@"Singular Links Handler");
NSLog(@"Singular deeplink received: %@", deeplink);
NSLog(@"Singular passthrough received: %@", passthrough);
NSLog(@"Singular isDeferred received: %@", isDeferred ? @"YES" : @"NO");
NSLog(@"Singular URL Params received: %@", urlParams);
#endif
// TODO: Navigate to appropriate screen based on deep link
// Add deep link handling code here. Navigate to appropriate screen.
}
SKAdNetwork は自動有効化: SDK バージョン 12.0.6 以降、SKAdNetwork はデフォルトで有効化されています。追加の設定は不要です。
SDK の初期化
アプリのアーキテクチャを選択
すべてのアプリエントリポイントで SDK を初期化します。初期化パターンは、アプリのアーキテクチャによって異なります。
どのアーキテクチャを使用していますか?
-
SceneDelegate:
プロジェクトに
SceneDelegate.swiftまたはSceneDelegate.mがあるか確認 -
SwiftUI:
アプリが
@main struct YourApp: Appで始まる - AppDelegate のみ: iOS 13 より前のアプリ、または SceneDelegate のないアプリ
最新の iOS:SceneDelegate(iOS 13 以降)
コードの追加場所:
SceneDelegate.swift
または
SceneDelegate.m
初期化するエントリポイント:
-
willConnectTo session- アプリの起動 -
continue userActivity- Universal Links -
openURLContexts- ディープリンクスキーム
import Singular
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// 1️⃣ App launch
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
// ANTI-SWIZZLING: Capture deep link parameters IMMEDIATELY before any
// other code runs. This prevents third-party SDKs from intercepting
// or modifying these values.
let userActivity = connectionOptions.userActivities.first
let urlContext = connectionOptions.urlContexts.first
let openUrl = urlContext?.url
#if DEBUG
// Log captured values to detect swizzling interference
print("[SWIZZLE CHECK] UserActivity captured:", userActivity?.webpageURL?.absoluteString ?? "none")
print("[SWIZZLE CHECK] URL Context captured:", openUrl?.absoluteString ?? "none")
print("IDFV:", UIDevice.current.identifierForVendor?.uuidString ?? "N/A")
#endif
// Create window from windowScene
guard let windowScene = scene as? UIWindowScene else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = UIViewController() // Replace with your root VC
window?.makeKeyAndVisible()
// Singular initialization - uses captured values to avoid swizzling conflicts
guard let config = getConfig() else { return }
// Pass Universal Link if available
if let userActivity = userActivity {
config.userActivity = userActivity
}
// Pass URL scheme if available
// CRITICAL for custom URL scheme attribution
if let openUrl = openUrl {
config.openUrl = openUrl
}
// Initialize Singular SDK
Singular.start(config)
}
// 2️⃣ Universal Links
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let config = getConfig() else { return }
config.userActivity = userActivity
// Initialize Singular SDK
Singular.start(config)
}
// 3️⃣ Deep link schemes
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let config = getConfig() else { return }
if let url = URLContexts.first?.url {
config.openUrl = url
}
// Initialize Singular SDK
Singular.start(config)
}
}
#import <Singular/Singular.h>
@implementation SceneDelegate
// 1️⃣ App launch
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session
options:(UISceneConnectionOptions *)connectionOptions {
// ANTI-SWIZZLING: Capture deep link parameters IMMEDIATELY before any
// other code runs. This prevents third-party SDKs from intercepting
// or modifying these values.
NSUserActivity *userActivity =
[[[connectionOptions userActivities]
allObjects] firstObject];
UIOpenURLContext *urlContext =
[[connectionOptions URLContexts]
allObjects].firstObject;
NSURL *openUrl = urlContext.URL;
#ifdef DEBUG
// Log captured values to detect swizzling interference
NSLog(@"[SWIZZLE CHECK] "
"UserActivity captured: %@",
userActivity.webpageURL);
NSLog(@"[SWIZZLE CHECK] "
"URL Context captured: %@",
openUrl);
#endif
// Create window from windowScene
UIWindowScene *windowScene = (UIWindowScene *)scene;
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
self.window.rootViewController = [[UIViewController alloc] init];
[self.window makeKeyAndVisible];
#ifdef DEBUG
// Print IDFV for testing in SDK Console
NSLog(@"IDFV: %@", [[[UIDevice currentDevice] identifierForVendor] UUIDString]);
#endif
// Singular initialization - uses captured values to avoid swizzling
SingularConfig *config = [self getConfig];
// Pass Universal Link if available
if (userActivity) {
config.userActivity = userActivity;
}
// Pass URL scheme if available
// CRITICAL for custom URL scheme
if (openUrl) {
config.openUrl = openUrl;
}
// Initialize Singular SDK
[Singular start:config];
}
// 2️⃣ Universal Links
- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
// ANTI-SWIZZLING: Capture userActivity immediately at method entry. Called
// when Universal Link is opened while app is running or backgrounded.
NSUserActivity *capturedActivity = userActivity;
#ifdef DEBUG
NSLog(@"[SWIZZLE CHECK] "
"continueUserActivity captured: %@",
capturedActivity.webpageURL);
#endif
SingularConfig *config = [self getConfig];
config.userActivity = capturedActivity;
// Initialize Singular SDK
[Singular start:config];
}
// 3️⃣ Deep link schemes
- (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts {
// ANTI-SWIZZLING: Capture URL immediately at method entry. Called
// when URL scheme is opened while app is running or backgrounded.
NSURL *capturedUrl =
[[URLContexts allObjects]
firstObject].URL;
#ifdef DEBUG
NSLog(@"[SWIZZLE CHECK] "
"openURLContexts captured: %@",
capturedUrl);
#endif
SingularConfig *config = [self getConfig];
if (capturedUrl) {
config.openUrl = capturedUrl;
}
// Initialize Singular SDK
[Singular start:config];
}
@end
最新の iOS:SwiftUI アプリ(iOS 14 以降)
コードの追加場所:
メインの
App
構造体ファイル
初期化するエントリポイント:
-
.onOpenURL(of: scenePhase)- カスタム URL スキームを処理 -
.onContinueUserActivity(of: scenePhase)- Universal Links を処理(Singular Deep Links) -
.onChange.active- ディープリンクが発生しなかった場合の初回起動時の初期化を処理。Deferred Deeplinks を処理します。
import SwiftUI
import Singular
@main
struct simpleSwiftUIApp: App {
@Environment(\.scenePhase) var scenePhase
@State private var hasInitialized = false
var body: some Scene {
WindowGroup {
ContentView()
// 1️⃣ Handle custom URL schemes (e.g., myapp://path)
.onOpenURL { url in
#if DEBUG
print("[Singular] URL Scheme:", url.absoluteString)
#endif
guard let config = getConfig() else { return }
config.openUrl = url
Singular.start(config)
hasInitialized = true
}
// 2️⃣ Handle Universal Links (e.g., https://links.your-domain.com)
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
#if DEBUG
print("[Singular] Universal Link:", userActivity.webpageURL?.absoluteString ?? "none")
#endif
guard let config = getConfig() else { return }
config.userActivity = userActivity
Singular.start(config)
hasInitialized = true
}
}
.onChange(of: scenePhase) { oldPhase, newPhase in
switch newPhase {
case .active:
// 3️⃣ Initialize ONLY on first launch if no deep link occurred
guard !hasInitialized else {
#if DEBUG
print("[Singular] Already initialized, skipping")
#endif
return
}
#if DEBUG
if let idfv = UIDevice.current.identifierForVendor?.uuidString {
print("[Singular] IDFV:", idfv)
}
#endif
guard let config = getConfig() else { return }
Singular.start(config)
hasInitialized = true
case .background:
#if DEBUG
print("[Singular] App backgrounded")
#endif
case .inactive:
#if DEBUG
print("[Singular] App inactive")
#endif
@unknown default:
break
}
}
}
// Add your getConfig() function here
// MARK: - Singular Configuration
private func getConfig() -> SingularConfig? {
// ... (same as above)
}
// Add your handleDeeplink() function here
// MARK: - Deep Link Handler
private func handleDeeplink(_ params: SingularLinkParams) {
// ... (same as above)
}
}
レガシー iOS:AppDelegate(iOS 13 より前)
コードの追加場所:
AppDelegate.swift
または
AppDelegate.m
初期化するエントリポイント:
-
didFinishLaunchingWithOptions- アプリの起動 -
continue userActivity- Universal Links -
open url- ディープリンクスキーム
import Singular
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
// 1️⃣ App launch
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ANTI-SWIZZLING: Capture deep link parameters IMMEDIATELY before any
// other code runs. This prevents third-party SDKs from intercepting
// or modifying these values.
let launchUrl = launchOptions?[.url] as? URL
let userActivityDictionary = launchOptions?[.userActivityDictionary] as? [String: Any]
let userActivity = userActivityDictionary?["UIApplicationLaunchOptionsUserActivityKey"] as? NSUserActivity
#if DEBUG
// Log captured values to detect swizzling interference
print("[SWIZZLE CHECK] Launch URL captured:", launchUrl?.absoluteString ?? "none")
print("[SWIZZLE CHECK] UserActivity captured:", userActivity?.webpageURL?.absoluteString ?? "none")
print("IDFV:", UIDevice.current.identifierForVendor?.uuidString ?? "N/A")
#endif
// Singular initialization - uses captured values to avoid swizzling conflicts
guard let config = getConfig() else { return true }
// Pass the entire launchOptions dictionary for Singular's internal processing
config.launchOptions = launchOptions
// Explicitly pass Universal Link if available
// CRITICAL for universal link attribution
if let userActivity = userActivity {
config.userActivity = userActivity
}
// Explicitly pass URL scheme if available
// CRITICAL for custom URL scheme attribution
if let launchUrl = launchUrl {
config.openUrl = launchUrl
}
// Initialize Singular SDK
Singular.start(config)
return true
}
// 2️⃣ Universal Links
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
#if DEBUG
print("[SWIZZLE CHECK] Universal Link handler called:", userActivity.webpageURL?.absoluteString ?? "none")
#endif
guard let config = getConfig() else { return true }
config.userActivity = userActivity
Singular.start(config)
return true
}
// 3️⃣ Deep link schemes
func application(_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
#if DEBUG
print("[SWIZZLE CHECK] URL Scheme handler called:", url.absoluteString)
#endif
guard let config = getConfig() else { return true }
config.openUrl = url
Singular.start(config)
return true
}
// Add your getConfig() function here
// MARK: - Singular Configuration
private func getConfig() -> SingularConfig? {
// ... (same as above)
}
// Add your handleDeeplink() function here
// MARK: - Deep Link Handler
private func handleDeeplink(_ params: SingularLinkParams) {
// ... (same as above)
}
}
#import "AppDelegate.h"
#import <Singular/Singular.h>
@implementation AppDelegate
// 1️⃣ App launch
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ANTI-SWIZZLING: Capture deep link parameters IMMEDIATELY before any
// other code runs. This prevents third-party SDKs from intercepting
// or modifying these values.
NSURL *launchUrl = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
NSDictionary *userActivityDictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsUserActivityDictionaryKey];
NSUserActivity *userActivity = [userActivityDictionary objectForKey:@"UIApplicationLaunchOptionsUserActivityKey"];
#if DEBUG
// Log captured values to detect swizzling interference
NSLog(@"[SWIZZLE CHECK] Launch URL captured: %@", launchUrl.absoluteString ?: @"none");
NSLog(@"[SWIZZLE CHECK] UserActivity captured: %@", userActivity.webpageURL.absoluteString ?: @"none");
NSLog(@"IDFV: %@", [UIDevice currentDevice].identifierForVendor.UUIDString ?: @"N/A");
#endif
// Singular initialization - uses captured values to avoid swizzling conflicts
SingularConfig *config = [self getConfig];
if (!config) {
return YES;
}
// Pass the entire launchOptions dictionary for Singular's internal processing
config.launchOptions = launchOptions;
// Explicitly pass Universal Link if available
// CRITICAL for universal link attribution
if (userActivity) {
config.userActivity = userActivity;
}
// Explicitly pass URL scheme if available
// CRITICAL for custom URL scheme attribution
if (launchUrl) {
config.openUrl = launchUrl;
}
// Initialize Singular SDK
[Singular start:config];
return YES;
}
// 2️⃣ Universal Links
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
#if DEBUG
NSLog(@"[SWIZZLE CHECK] Universal Link handler called: %@", userActivity.webpageURL.absoluteString ?: @"none");
#endif
SingularConfig *config = [self getConfig];
if (!config) {
return YES;
}
config.userActivity = userActivity;
[Singular start:config];
return YES;
}
// 3️⃣ Deep link schemes
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
#if DEBUG
NSLog(@"[SWIZZLE CHECK] URL Scheme handler called: %@", url.absoluteString);
#endif
SingularConfig *config = [self getConfig];
if (!config) {
return YES;
}
config.openUrl = url;
[Singular start:config];
return YES;
}
#pragma mark - Singular Configuration
- (SingularConfig *)getConfig {
}
#pragma mark - OPTIONAL: Deep link handler implementation
- (void)handleDeeplink:(SingularLinkParams *)params {
}
@end
インストールの確認
プリフライト チェックリスト
統合をビルドおよびテストする前に、以下の項目を確認してください。
- CocoaPods、SPM、または手動フレームワークで SDK をインストール
- Swift ブリッジングヘッダーを作成(Swift を使用する場合)
-
getConfig()関数を実装 -
Singular.start(config)をすべてのエントリポイントで呼び出し - SDK Key と SDK Secret を設定に追加
- ATT タイムアウトを設定(ATT プロンプトを表示する場合のみ)
- ディープリンクハンドラーを設定(ディープリンクを使用する場合のみ)
- アプリがエラーなくビルドされる
次のステップ:
- アプリをビルドして実行
- IDFV の print 文をコンソールで確認
- IDFV を使って Singular SDK Console でテスト
- 1〜2 分以内に SDK Console にセッションが表示されることを確認
オプション:App Tracking Transparency (ATT)
IDFA アクセスのためのユーザー許可を要求し、アトリビューションの精度を向上させるために ATT を設定します。
以下の場合は、このセクションをスキップしてください: アプリで ATT プロンプトを表示していない場合。
なぜ ATT 同意を要求するのか?
IDFA のメリット
iOS 14.5 以降、アプリはデバイスの IDFA(Identifier for Advertisers)にアクセスするためのユーザー許可を要求する必要があります。
IDFA ありとなしのアトリビューションの比較:
- IDFA あり: デバイスレベルでの正確なアトリビューションと精度の高いインストールマッチング
- IDFA なし: IP、ユーザーエージェント、デバイスフィンガープリンティングを使用した確率的アトリビューション
推奨: アトリビューションの精度を高めるため、ATT 同意を要求してください。Singular は IDFA なしでもアトリビューションが可能ですが、精度は低下します。
ATT 遅延の設定
SDK 初期化の遅延
最初のセッションを Singular に送信する前に、ユーザーの ATT 応答を待つためのタイムアウトを追加します。
重要: SDK は、最初のセッションを送信する前に ATT 同意を待つ必要があります。そうしないと、最初のアトリビューション イベントに IDFA が含まれません。
func getSingularConfig() -> SingularConfig? {
guard let config = SingularConfig(
apiKey: "YOUR_SDK_KEY",
andSecret: "YOUR_SDK_SECRET"
) else {
return nil
}
// Wait up to 300 seconds for ATT response
config.waitForTrackingAuthorizationWithTimeoutInterval = 300
return config
}
- (SingularConfig *)getSingularConfig {
SingularConfig *config = [[SingularConfig alloc]
initWithApiKey:@"YOUR_SDK_KEY"
andSecret:@"YOUR_SDK_SECRET"];
// Wait up to 300 seconds for ATT response
config.waitForTrackingAuthorizationWithTimeoutInterval = 300;
return config;
}
ATT フローのタイムライン
ATT 遅延を設定した場合の動作は次のとおりです:
- アプリの起動: SDK はイベントの記録を開始しますが、まだ送信しません
- ATT プロンプト: アプリが ATT 同意ダイアログを表示
- ユーザーの応答: ユーザーが許可を付与または拒否
- SDK がデータを送信: SDK はキューに入れられたイベントを IDFA(許可された場合)と共にすぐに送信
- タイムアウト フォールバック: 応答なしで 300 秒経過すると、SDK は IDFA なしでデータを送信
ベストプラクティス: アトリビューションの IDFA 取得を最大化するため、ATT プロンプトはできるだけ早く(理想的にはアプリの初回起動時に)表示してください。