Android SDK - データプライバシー

データプライバシー法の遵守

GDPR、CCPA、その他の消費者プライバシー規制におけるユーザーの同意の選択を Singular に通知することで、プライバシーに準拠したデータ収集を実装します。

ユーザーが第三者との情報共有に同意または拒否した場合、Singular のプライバシーメソッドを使用してその選択を伝達します。これにより、 California Consumer Privacy Act (CCPA) などの規制を遵守し、パートナーがユーザーのプライバシー設定を尊重できるようになります。

詳しく見る: Singular がプライバシー同意をどのように処理するかの詳細については、 ユーザープライバシーとデータ共有の制限 を参照してください。


データ共有の制限

第三者へのデータ共有の制御

ユーザーが第三者パートナーと個人データを共有することに同意したかどうかを、 limitDataSharing メソッドを使用して Singular に通知します。

メソッドシグネチャ:

public static void limitDataSharing(boolean shouldLimitDataSharing);

パラメーター:

  • false: ユーザーがオプトインし、データの共有に同意した
  • true: ユーザーがオプトアウトし、データの共有に同意しなかった

重要: このメソッドは任意ですが、アトリビューションデータの共有に影響します。一部のパートナーは、ユーザーがオプトインしたことが明示的に通知された場合にのみ、完全なアトリビューション情報を共有します。

使用例

Kotlin Java
// User has opted in to share their data
Singular.limitDataSharing(false)

// User has opted out and declined to share their data
Singular.limitDataSharing(true)

// Example: Set based on user preference
fun handlePrivacyConsent(userConsented: Boolean) {
    // Pass inverse: false = opted in, true = opted out
    Singular.limitDataSharing(!userConsented)

    Log.d("Privacy", "Data sharing: ${if (userConsented) "Enabled" else "Limited"}")
}

動作の仕組み:

Singular はこの設定を ユーザープライバシーポストバック で使用し、規制遵守のためにこれを必要とするパートナーに渡します。


イベント単位のデータ共有制限

単一イベントのデータ共有を上書き

他のイベント引数とともに Attributes.sngAttrLimitDataSharing 属性を渡すことで、単一のイベントまたはカスタム収益呼び出しに対して、グローバルな limitDataSharing 設定を上書きできます。これは、ユーザーがアクションと同時に同意を更新し、後続のイベントに対する SDK 全体の設定を変更することなく、その特定のイベントに新しい選択を即座に反映させたい場合に役立ちます。

許容値:

  • false: このイベントに限ってユーザーがオプトイン
  • true: このイベントに限ってユーザーがオプトアウト

重要: この属性は Boolean である必要があります。ブール値以外の入力は無視され、リクエストはグローバルな limitDataSharing 設定にフォールバックします。いずれの場合でも、この属性はリクエストが送信される前にイベントの引数から削除されるため、イベントペイロードには表示されません。

使用例

Kotlin Java
// Example 1: Standard event, opt out only for this event
val args = JSONObject()
    .put(Attributes.sngAttrLimitDataSharing.toString(), true)
    .put("order_id", "12345")

Singular.event("checkout_completed", args.toString())

// Example 2: Custom revenue, opt in only for this event
val attributes = mutableMapOf<String, Any>().apply {
    put(Attributes.sngAttrLimitDataSharing.toString(), false)
    put("sku", "premium_monthly")
}

Singular.customRevenue("premium_purchase", "USD", 9.99, attributes)

動作の仕組み:

有効なブール値が指定されると、SDK は該当属性をイベント引数から削除し、リクエストの data_sharing_options.limit_data_sharing フィールドに書き込みます — これにより、その単一リクエストに限ってグローバルな limitDataSharing 設定が上書きされます。グローバル設定と getLimitDataSharing の結果は変更されないため、属性を指定しない後続のイベントは引き続きグローバルな選択を使用します。


GDPR 準拠メソッド

GDPR (一般データ保護規則) およびその他のプライバシー規制を遵守するために、ユーザートラッキング同意を管理し SDK 機能を制御します。

トラッキング同意管理

trackingOptIn

GDPR オプトインイベントを Singular サーバーに送信して、ユーザーのトラッキング同意を明示的に記録します。

メソッドシグネチャ:

Singular.trackingOptIn()

使用するタイミング:

  • GDPR 準拠: GDPR 規制地域でユーザーがトラッキングに明示的に同意したときに呼び出す
  • 同意の記録: Singular のシステム内で、ユーザーが GDPR 同意を提供したものとしてマーク
  • デフォルトの動作: この呼び出しがなくても SDK はトラッキングを継続するが、同意を特定して記録することはない
Kotlin Java
// User accepted tracking consent
Singular.trackingOptIn()

// Example: Call after consent dialog
fun onUserAcceptedTracking() {
    Singular.trackingOptIn()
    Log.d("GDPR", "User opted in to tracking")
}

トラッキング制御メソッド

stopAllTracking

このデバイスの現在のユーザーに対する SDK のすべてのトラッキング活動を完全に無効化します。

メソッドシグネチャ:

Singular.stopAllTracking()

重要な警告: このメソッドは resumeAllTracking() が呼び出されるまで SDK を恒久的に無効化します。無効化された状態はアプリの再起動後も維持され、プログラムによってのみ元に戻すことができます。

動作:

  • 即時適用: すべてのトラッキング、イベント報告、データ収集を即座に停止
  • 永続的な状態: アプリを閉じて再度開いた後も無効化された状態が継続
  • 自動リセットなし: 再度有効にするには resumeAllTracking() を明示的に呼び出す必要がある
Kotlin Java
// User declined all tracking
Singular.stopAllTracking()

// Example: Handle user opt-out
fun onUserDeclinedTracking() {
    Singular.stopAllTracking()
    Log.d("Privacy", "All tracking stopped")

    // Optionally store preference
    saveUserTrackingPreference(false)
}

resumeAllTracking

stopAllTracking() で停止されたトラッキングを再度有効にします。

メソッドシグネチャ:

Singular.resumeAllTracking()

使用ケース:

  • 同意の変更: ユーザーがプライバシー設定を変更し、トラッキングに再度オプトインした
  • プライバシー設定: ユーザーがアプリの設定メニューで同意を更新した
  • 地域コンプライアンス: ユーザーが規制対象外の地域に移動した場合にトラッキングを再有効化
Kotlin Java
// User opted back in to tracking
Singular.resumeAllTracking()

// Example: Handle consent update
fun onUserResumedTracking() {
    Singular.resumeAllTracking()
    Log.d("Privacy", "Tracking resumed")

    // Optionally update stored preference
    saveUserTrackingPreference(true)
}

isAllTrackingStopped

現在のユーザーに対してトラッキングが無効化されているかどうかを確認します。

メソッドシグネチャ:

public static boolean isAllTrackingStopped();

戻り値:

  • true: stopAllTracking() によってトラッキングが現在停止されている
  • false: トラッキングがアクティブ (停止されていないか、再開された状態)

SDK が初期化されていない場合、それ以前のトラッキング状態に関係なく false を返します。この値を信頼する前に、 Singular.init() が完了したことを必ず確認し、 false を「アクティブにトラッキング中」ではなく「停止されていない、またはまだ初期化されていない」と解釈してください。

Kotlin Java
// Check current tracking status
val isTrackingStopped = Singular.isAllTrackingStopped()

// Example: Display privacy status in settings
fun getPrivacyStatusText(): String {
    return if (Singular.isAllTrackingStopped()) {
        "Tracking: Disabled"
    } else {
        "Tracking: Enabled"
    }
}

// Example: Sync UI with tracking state
fun updatePrivacyToggle() {
    val isStopped = Singular.isAllTrackingStopped()
    privacyToggle.isChecked = !isStopped
    Log.d("Privacy", "Current tracking state: ${if (isStopped) "Stopped" else "Active"}")
}

児童プライバシー保護

trackingUnder13

COPPA (児童オンラインプライバシー保護法) およびその他の児童プライバシー規制を遵守するために、ユーザーが 13 歳未満であることを Singular に通知します。

メソッドシグネチャ:

Singular.trackingUnder13()

コンプライアンス要件:

  • COPPA 準拠: 米国で 13 歳未満の児童からデータを収集するアプリで必須
  • 年齢制限コンテンツ: 登録または年齢確認時にユーザーが 13 歳未満として識別された場合に使用
  • トラッキングの制限: 児童プライバシー保護法を遵守するためにデータ収集を制限
Kotlin Java
// User identified as under 13
Singular.trackingUnder13()

// Example: Call after age verification
fun onAgeVerified(userAge: Int) {
    if (userAge < 13) {
        Singular.trackingUnder13()
        Log.d("Privacy", "COPPA mode enabled for user under 13")
    }
}

重要: ユーザーが 13 歳未満であると判明したら、できるだけ早くこのメソッドを呼び出してください。理想的にはアプリの初期化時、または年齢確認の直後が望ましいです。これにより、それ以降のすべてのトラッキングが児童プライバシー規制を遵守するようになります。


setLimitAdvertisingIdentifiers

混合オーディエンスアプリの場合、SDK 初期化後に広告識別子 (Android の GAID) の収集と使用を制限します。

メソッドシグネチャ:

public static void setLimitAdvertisingIdentifiers(boolean enabled);

パラメーター:

  • enabled: 広告識別子の収集を制限するには true を渡し、通常の収集に戻すには false を渡します。

構成時のバリアントと混同しないでください。 ランタイムメソッド Singular.setLimitAdvertisingIdentifiers(boolean) はブール引数を必要とするのに対し、構成時メソッド SingularConfig.withLimitAdvertisingIdentifiers() は引数を取らず、無条件に制限を有効にします。ランタイムメソッドを引数なしで呼び出すとコンパイルされません。

使用ケース:

  • 混合オーディエンスアプリ: アプリ起動後に年齢が決定される、成人と児童の両方を対象とするアプリ
  • 動的プライバシー制御: ユーザーの行動やアクセスするコンテンツに応じてトラッキングを調整
  • ランタイム制限: 初期 SDK 設定後に広告識別子の制限を適用
Kotlin Java
// Limit advertising identifiers after initialization
Singular.setLimitAdvertisingIdentifiers(true)

// Example: Mixed audience app with age gate
fun onKidsModeSwitched(isKidsMode: Boolean) {
    if (isKidsMode) {
        Singular.setLimitAdvertisingIdentifiers(true)
        Log.d("Privacy", "Advertising identifiers limited for kids mode")
    }
}

// Example: Content-based restrictions
fun onViewingChildrensContent() {
    Singular.setLimitAdvertisingIdentifiers(true)
    Log.d("Privacy", "Ad identifiers restricted for children's content")
}

構成での代替手段: SDK 起動前にプライバシー要件を把握している場合は、 SingularConfig.withLimitAdvertisingIdentifiers() を使用して SDK 初期化時に広告識別子を制限することもできます。

構成メソッド

プライバシー要件を事前に把握しているアプリの場合、SDK 初期化時に広告識別子の制限を設定します。

Kotlin Java
// Limit advertising identifiers at initialization
val config = SingularConfig("SDK_KEY", "SDK_SECRET")
    .withLimitAdvertisingIdentifiers()

Singular.init(applicationContext, config)

実装のベストプラクティス

完全なプライバシー管理の例

ユーザーの選好を尊重し、規制を遵守する包括的なプライバシー制御を実装します。

Kotlin Java
class PrivacyManager(private val context: Context) {

    private val prefs = context.getSharedPreferences("privacy_prefs", Context.MODE_PRIVATE)

    // Initialize privacy settings on app start
    fun initializePrivacy() {
        val hasUserConsent = getUserConsent()
        val allowDataSharing = getDataSharingPreference()
        val userAge = getUserAge()

        // Apply stored preferences
        if (hasUserConsent) {
            Singular.trackingOptIn()
            Singular.resumeAllTracking()
        } else {
            Singular.stopAllTracking()
        }

        // Set data sharing preference
        Singular.limitDataSharing(!allowDataSharing)

        // Handle children's privacy
        if (userAge > 0 && userAge < 13) {
            Singular.trackingUnder13()
            Singular.setLimitAdvertisingIdentifiers(true)
        }

        Log.d("Privacy", "Initialized: consent=$hasUserConsent, sharing=$allowDataSharing, age=$userAge")
    }

    // User accepts tracking via consent dialog
    fun userAcceptedTracking() {
        saveUserConsent(true)
        Singular.trackingOptIn()
        Singular.resumeAllTracking()
        Log.d("Privacy", "User accepted tracking")
    }

    // User declines tracking
    fun userDeclinedTracking() {
        saveUserConsent(false)
        Singular.stopAllTracking()
        Log.d("Privacy", "User declined tracking")
    }

    // User updates data sharing preference
    fun setDataSharingEnabled(enabled: Boolean) {
        saveDataSharingPreference(enabled)
        // Note: limitDataSharing uses inverse logic
        Singular.limitDataSharing(!enabled)
        Log.d("Privacy", "Data sharing: ${if (enabled) "Enabled" else "Limited"}")
    }

    // Handle age verification result
    fun onAgeVerified(age: Int) {
        saveUserAge(age)
        if (age < 13) {
            Singular.trackingUnder13()
            Singular.setLimitAdvertisingIdentifiers(true)
            Log.d("Privacy", "COPPA restrictions applied for user under 13")
        }
    }

    // Get current tracking status
    fun isTrackingEnabled(): Boolean {
        return !Singular.isAllTrackingStopped()
    }

    // Private helper methods
    private fun getUserConsent(): Boolean {
        return prefs.getBoolean("user_consent", false)
    }

    private fun saveUserConsent(consent: Boolean) {
        prefs.edit().putBoolean("user_consent", consent).apply()
    }

    private fun getDataSharingPreference(): Boolean {
        return prefs.getBoolean("data_sharing", false)
    }

    private fun saveDataSharingPreference(enabled: Boolean) {
        prefs.edit().putBoolean("data_sharing", enabled).apply()
    }

    private fun getUserAge(): Int {
        return prefs.getInt("user_age", 0)
    }

    private fun saveUserAge(age: Int) {
        prefs.edit().putInt("user_age", age).apply()
    }
}

ベストプラクティス:

  • 永続的なストレージ: ユーザー設定を SharedPreferences またはセキュアなストレージに保存
  • 早期の初期化: 可能であれば SDK 初期化前にプライバシー設定を適用
  • UI 同期: isAllTrackingStopped() を使用して設定 UI と実際の SDK 状態を同期
  • 明確なコミュニケーション: アプリ設定で明確でアクセスしやすいプライバシー制御を提供
  • 年齢確認: 児童を対象とするアプリには堅牢な年齢確認を実装
  • 併用する制御: 13 歳未満のユーザーには trackingUnder13() setLimitAdvertisingIdentifiers(true) の両方を適用