Flutter SDK - SKAdNetworkのサポート

ドキュメント

SKAdNetworkのサポート

SKAdNetworkは、iOSアプリインストールキャンペーンのためのAppleのプライバシー重視のアトリビューションフレームワークです。Singular Flutter SDKはデフォルトのマネージドモードでSKAdNetworkを有効にし、ダッシュボードで設定したコンバージョンモデルに基づいてSingularが自動的にコンバージョン値を更新します。

追加の設定は必要ありません:最新のFlutter SDKを使用している場合、SKAdNetworkはすぐに動作します。基本的な機能にはコードの変更や追加設定は必要ありません。

SKANモードについて

マネージドモード(デフォルト)

マネージドモードでは、Singularはダッシュボードで設定したコンバージョンモデルに基づいてコンバージョン値の更新を自動的に処理します。これは最小限のコードで最適なコンバージョントラッキングを提供するため、ほとんどのアプリに推奨されるアプローチです。

  • 自動更新:Singularはユーザーイベントと設定されたモデルに基づいてすべてのコンバージョン値の更新を管理します。
  • ダッシュボードの設定:コードを変更することなく、Singularダッシュボードでコンバージョンモデルをデザインします。
  • 最適化:Appleの制約の中でコンバージョン値の更新を最大化するSingularの専門知識をご利用ください。
  • 24時間ウィンドウ管理:SingularはSKAdNetworkの24時間更新ウィンドウをインテリジェントに処理し、データ収集を最大化します。

マニュアルモード(上級者向け)

マニュアルモードでは、変換値の更新を完全にコントロールすることができ、SKANの変換値をいつ、どのように更新するかを決定するカスタムロジックを実装することができます。このモードは、マネージドモードでは対応できない特定の要件がある場合にのみ使用します。

高度な機能です:マニュアルモードでは、変換値の更新ウィンドウや制限など、AppleのSKAdNetworkの制約を理解し、慎重に実装する必要があります。ほとんどのアプリはマネージドモードを使用してください。

SKAdNetworkサポートを無効にする

SKAdNetwork トラッキングはデフォルトで有効になっています。無効にするには、SingularConfigオブジェクトをビルドする際に、skAdNetworkEnabled コンフィギュレーションプロパティをfalseに設定してください。

Dart
import 'package:singular_flutter_sdk/singular_config.dart';

SingularConfig config = SingularConfig('API_KEY', 'SECRET');
config.skAdNetworkEnabled = false; // Disable SKAdNetwork

マニュアルモードの設定

カスタム変換値ロジックを実装するには、Manual Modeを有効にし、提供されるSDKメソッドを使用して、アプリのライフサイクル全体を通して変換値を更新および監視します。

マニュアルモードを有効にする

SingularConfigオブジェクトをビルドする際に、manualSkanConversionManagement コンフィギュレーションプロパティをtrueに設定し、変換値の更新を制御できるようにします。

Dart
import 'package:singular_flutter_sdk/singular_config.dart';

SingularConfig config = SingularConfig('API_KEY', 'SECRET');
config.manualSkanConversionManagement = true; // Enable manual mode

重要:手動更新メソッドは、manualSkanConversionManagement が有効な場合にのみ機能します。マネージドモードが有効な場合、手動更新は無視されます。

変換値の更新(SKAN 2.0-3.0)

skanUpdateConversionValue メソッドを使用して、カスタムロジックに基づいてSKAdNetworkの変換値を手動で更新します。変換値は0~63の整数である必要があります。

メソッドの署名

Dart
static void skanUpdateConversionValue(int conversionValue)

使用例

Dart
import 'package:singular_flutter_sdk/singular.dart';
import 'dart:io';

// User completed signup - update conversion value to 7
void onUserSignUp() {
  if (Platform.isIOS) {
    // Track the sign-up event
    Singular.event('SignUp');

    // Update SKAN conversion value
    Singular.skanUpdateConversionValue(7);
    print('Conversion value updated to 7');
  }
}

// User completed purchase - update based on purchase amount
void onPurchaseComplete(double purchaseAmount) {
  if (Platform.isIOS) {
    // Track revenue event
    Singular.customRevenue('Purchase', 'USD', purchaseAmount);

    // Calculate conversion value based on purchase tier
    int conversionValue = calculateConversionValue(purchaseAmount);
    Singular.skanUpdateConversionValue(conversionValue);
    print('Conversion value updated to $conversionValue');
  }
}

int calculateConversionValue(double amount) {
  // Your custom logic to determine conversion value
  if (amount >= 100) return 63;  // High value
  if (amount >= 50) return 40;   // Medium value
  if (amount >= 10) return 20;   // Low value
  return 10;                      // Minimal value
}

変換値の更新(SKAN 4.0)

iOS 16.1+では、skanUpdateConversionValues メソッドを使用して、SKAdNetwork 4.0の変換値を細かい値、粗い値、およびロックパラメータで更新します。これにより、変換値の更新をより詳細に制御できます。

メソッドの署名

Dart
static void skanUpdateConversionValues(
  int conversionValue,  // Fine value (0-63)
  int coarse,           // Coarse value (0=low, 1=medium, 2=high)
  bool lock             // Lock status
)

使用例

Dart
import 'package:singular_flutter_sdk/singular.dart';
import 'dart:io';

void updateSKAN4ConversionValue(
  int fineValue, 
  String coarseValue,
  bool shouldLock
) {
  if (Platform.isIOS) {
    // Map coarse value string to number
    Map<String, int> coarseMap = {
      'low': 0, 
      'medium': 1, 
      'high': 2
    };

    // Update SKAdNetwork 4.0 conversion values
    Singular.skanUpdateConversionValues(
      fineValue,
      coarseMap[coarseValue] ?? 0,
      shouldLock
    );

    print('SKAN 4.0 updated: fine=$fineValue, coarse=$coarseValue, lock=$shouldLock');
  }
}

// Example: High-value user completes tutorial
void onTutorialComplete() {
  updateSKAN4ConversionValue(15, 'medium', false);
}

// Example: Premium purchase - lock the value
void onPremiumPurchase() {
  updateSKAN4ConversionValue(63, 'high', true);
}

現在の変換値の取得

Singular SDKが追跡している現在の変換値を取得します。これは現在の状態に基づいた条件ロジックを実装するのに便利で、マネージドモードとマニュアルモードの両方で動作します。

メソッドのシグネチャ

Dart
static Future<int> skanGetConversionValue()

使用例

Dart
import 'package:singular_flutter_sdk/singular.dart';
import 'dart:io';

Future<void> checkAndUpdateConversionValue() async {
  if (Platform.isIOS) {
    int currentValue = await Singular.skanGetConversionValue();
    print('Current conversion value: $currentValue');

    // Only update if current value is below threshold
    if (currentValue < 30) {
      Singular.skanUpdateConversionValue(30);
      print('Updated conversion value to 30');
    }
  }
}

コンバージョン値の更新を監視する

コンバージョン値が変更されるたびにリアルタイムの通知を受け取るハンドラを設定します。これにより、コンバージョン値の更新に反応し、アナリティクスを記録したり、他のアプリの動作をトリガーしたりすることができます。

設定方法

SDKを初期化する際に、conversionValueUpdatedCallback プロパティを使用してコンバージョン値更新ハンドラを設定します。

Dart
import 'package:singular_flutter_sdk/singular.dart';
import 'package:singular_flutter_sdk/singular_config.dart';

void initializeSingularSDK() {
  SingularConfig config = SingularConfig('API_KEY', 'SECRET');

  // Set up conversion value update handler
  config.conversionValueUpdatedCallback = (int conversionValue) {
    print('Conversion value updated to: $conversionValue');

    // Log the update to your analytics
    logConversionValueUpdate(conversionValue);

    // Trigger app-specific behavior
    if (conversionValue >= 50) {
      unlockPremiumFeature();
    }
  };

  Singular.start(config);
}

void logConversionValueUpdate(int value) {
  // Your analytics logging logic
  print('Analytics: SKAN CV = $value');
}

void unlockPremiumFeature() {
  // Your custom logic
  print('Premium feature unlocked based on high conversion value');
}

ベストプラクティスコンバージョン値ハンドラを使用して、アプリ全体で現在のコンバージョン状態の同期ビューを維持します。これは、デバッグやカスタムロジックが正しく動作することを確認するために特に便利です。


App Tracking Transparency(ATT)のサポート

App Tracking Transparency (ATT)は、デバイスのIDFA (Identifier for Advertisers)にアクセスしてユーザーデータを共有する前に、ユーザーの同意を必要とするAppleのプライバシーフレームワークです。ATTを正しく実装することは、iOSのアトリビューションとユーザー獲得キャンペーンの精度を最大化するために非常に重要です。

ATTがアトリビューションに重要な理由

iOS 14.5以降、アプリはIDFAにアクセスする前に、ATTフレームワークを通じてユーザーの許可を要求する必要があります。IDFAがなくてもフィンガープリンティングや確率的な方法でアトリビューションは可能ですが、IDFAがあることでアトリビューションの精度が大幅に向上し、決定論的なマッチングが可能になります。

  • 決定論的アトリビューション:IDFAは、広告インプレッションとインストールを直接結びつける正確なデバイスレベルのアトリビューションを可能にします。
  • 広告ネットワークの最適化:広告ネットワークは、IDFAにアクセスすることで、キャンペーンをより最適化し、より正確なレポートを提供できます。
  • ユーザーレベルのインサイト:IDFAにアクセスすることで、より詳細なユーザー行動分析とコホート追跡が可能になります。

推奨ATTプロンプトを実装し、ユーザーの同意を求めることを強くお勧めします。ユーザーにメリット(パーソナライズされた広告、より良いアプリ体験)を説明し、オプトイン率を最大化する。

実装要件

iOS 14.5+(iOS 18を含む)では、トラッキングのためにIDFAにアクセスする前に、ATTrackingManagerフレームワークを使用してユーザーの同意を求めます。Singular SDKはATTをサポートしており、同意の前に初期化を行い、同意が得られるかタイムアウトが発生するまでイベントを遅延させることができます。

ステップ1:ATTフレームワーク設定を追加する

Info.plistファイルをユーザー向けの使用説明で更新することで、ATTフレームワークをサポートするようにiOSアプリを設定します。

  1. Info.plistを開く:FlutterプロジェクトのiOS Info.plistファイル(ios/Runner/Info.plist )に移動します。
  2. 使い方の説明を追加する:あなたのアプリがなぜトラッキング許可を必要とするのかの明確な説明とともに、NSUserTrackingUsageDescription キーを追加します。
Info.plist
<key>NSUserTrackingUsageDescription</key>
<string>This app uses tracking to provide personalized ads and improve your experience.</string>

重要:使用法の説明はATTプロンプトでユーザーに表示されます。トラッキングがユーザーにどのような利益をもたらすかについて、明確かつ簡潔に、そして正直に記述してください。

ステップ2:ATTサポートパッケージのインストール

アプリのATT機能を有効にするために、Flutter ATTサポートパッケージをインストールしましょう。app_tracking_transparency プラグインをお勧めします。

依存関係を追加する

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  singular_flutter_sdk: ^1.8.0
  app_tracking_transparency: ^2.0.4

依存関係を追加したら、flutter pub get を実行してパッケージをインストールします。

bash
flutter pub get

代替パッケージ私たちはapp_tracking_transparencyを推奨しますが、同様の機能を提供するFlutter ATTプラグインなら何でも使えます。 プラグインがiOS 14.5+をサポートしていることを確認してください。

ステップ3:SDK待ちタイムアウトの設定

waitForTrackingAuthorizationWithTimeoutInterval プロパティを設定して、初期化する前にユーザーのATT応答を待つようにSingular SDKを設定します。 この遅延により、ユーザーが許可を与えた場合にIDFAがキャプチャされるようになります。

重要です:Singular SDKが最初のセッションを送信する前に、必ずATTの同意を要求し、IDFAを取得してください。これを怠ると、そのデバイスのアトリビューションデータのIDFAが永久に失われます。

Dart
import 'package:singular_flutter_sdk/singular_config.dart';

SingularConfig config = SingularConfig('API_KEY', 'SECRET');
config.waitForTrackingAuthorizationWithTimeoutInterval = 300; // Wait up to 5 minutes

推奨値アプリがATTプロンプトを表示する場合は、タイムアウトを300秒(5分)に設定してください。これにより、プロンプトの表示が遅れたり表示されなかったりしても、ユーザーエクスペリエンスが低下することなく、ユーザーがプロンプトを見て応答するのに十分な時間が確保されます。

ステップ4:ATT同意を要求する

アプリにATTリクエストフローを実装し、ユーザーエクスペリエンスの適切なタイミングでトラッキング許可をユーザーに促します。

Dart
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:singular_flutter_sdk/singular.dart';
import 'package:singular_flutter_sdk/singular_config.dart';
import 'package:app_tracking_transparency/app_tracking_transparency.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    initializeApp();
  }

  Future<void> initializeApp() async {
    if (Platform.isIOS) {
      // Request ATT authorization
      final trackingStatus = await AppTrackingTransparency.requestTrackingAuthorization();

      // Log the user's response
      print('ATT Status: $trackingStatus');
      // Possible values: TrackingStatus.authorized, .denied, .restricted, .notDetermined
    }

    // Initialize Singular SDK (configured with wait timeout)
    SingularConfig config = SingularConfig('API_KEY', 'SECRET');
    config.waitForTrackingAuthorizationWithTimeoutInterval = 300;
    config.enableLogging = true;

    Singular.start(config);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

ATTフローを理解する

waitForTrackingAuthorizationWithTimeoutInterval を使用して初期化遅延を設定すると、アプリフローは以下のように動作します:

  1. アプリが開くと、Singular SDKはセッションとユーザーイベントの記録を開始しますが、まだSingularサーバーには送信しません。
  2. App Tracking Transparencyの同意が許可/拒否されるか、設定された時間が経過すると、SDKはセッションとキューに入れられたイベントをSingularサーバーに送信します(IDFAの有無は問いません)。
  3. Singularは、IDFAが利用可能であればそれを利用してアトリビューションプロセスを開始します。

ATTシナリオ

次の表は、この統合を使用するシナリオをまとめたものです:

シナリオ IDFAの利用可能性
ユーザーは同意のダイアログを見て、設定された時間が経過する前に同意する。 IDFA が利用可能
ユーザーが同意ダイアログを表示し、設定時間が経過する前に同意を拒否する。 IDFAが利用できない
設定時間が経過し、同意ダイアログが表示され、同意する。 IDFA は、同意の後に報告されるユーザーイベントでのみ利用可能である。
設定時間が経過し、同意ダイアログが表示され、同意が拒否される。 IDFA は利用できない
ユーザが同意ダイアログを表示し、アクションを起こさずにアプリを終了し、設定時間が経過した後にアプリを開いて同意を与えた。 アプリが再び開かれると、キューに入れられたイベントがSingularサーバーに送信されます。同意が付与された後に追跡されるイベントには IDFA が関連付けられます。
ユーザーは同意ダイアログを表示され、アクションを起こさずにアプリを終了し、後でアプリを開いて同意を拒否します。 キューに入れられたイベントは、アプリが再び開かれたときにSingularサーバーに送信されます。IDFAは、これらのイベントやその後に追跡されるイベントでは使用できません。

ATTベストプラクティス

  • メッセージングを事前に促す:トラッキング許可が必要な理由と、それがユーザーにどのようなメリット(より良い広告、より良い体験)をもたらすかを説明するATT前の画面をユーザーに見せましょう。これにより、オプトイン率が大幅に向上します。
  • タイミングが重要:初回起動直後ではなく、アプリフローの自然なタイミングでATTプロンプトを表示しましょう。まずはユーザーにアプリを体験してもらい、信頼を築きましょう。
  • タイムアウトの設定: waitForTrackingAuthorizationWithTimeoutInterval を30~300秒に設定します。タイムアウト後、SingularはSKAN 4.0のアトリビューションで処理を進めます(IDFAなし)。
  • 徹底的にテストする:許可されたシナリオと拒否されたシナリオの両方をテストし、ユーザーの選択に関係なくアプリが正しく機能することを確認します。
  • ユーザーの選択を尊重してください:トラッキングを拒否したユーザーに対して何度もプロンプトを表示したり、オプトインを迫るような攻撃的なメッセージを表示したりしないでください。
  • エラー処理: restricted (ペアレンタルコントロールなど)またはnotDetermined のトラッキングステータスをチェックし、分析のためにログを記録します。
  • SKAN 4.0との統合:SKANのポストバックを最適化するために、コンバージョン値の更新がATTの同意と一致していることを確認する(例えば、イベントを値0~63にマッピングするためにSingularのダッシュボードを使用する)。

App Storeレビュー:ATTを適切に実装していないアプリや、フレームワークを回避しようとするアプリは、App Storeの審査で却下される可能性があります。Appleのガイドラインに従って実装し、ユーザーのプライバシーの選択を尊重するようにしてください。

その他のリソース