遵守数据隐私法
通过通知 Singular 用户同意 GDPR、CCPA 和其他消费者隐私法规的选择,实施符合隐私法规的数据收集。
当用户同意或拒绝与第三方共享其信息时,使用 Singular 的隐私方法来传达他们的选择。这将确保遵守《加州消费者隐私法案》(CCPA)等法规,并使合作伙伴尊重用户的隐私偏好。
了解更多信息:有关Singular如何处理隐私同意的详细信息,请参阅用户隐私和限制数据共享。
限制数据共享
控制第三方数据共享
通知Singular用户是否同意使用LimitDataSharing方法与第三方合作伙伴共享个人数据。
方法签名:
static void LimitDataSharing(bool shouldLimitDataSharing)
参数:
- false:用户已选择并同意共享其数据
- true: true:用户已退出,不同意共享其数据
重要:虽然此方法是可选的,但它会影响属性数据的共享。一些合作伙伴只有在明确通知用户已选择加入时,才会共享完整的归因信息。
使用示例
// User has opted in to share their data
void AYourGameMode::OnUserOptedInToDataSharing()
{
USingularSDKBPLibrary::LimitDataSharing(false);
UE_LOG(LogTemp, Log, TEXT("Data sharing enabled"));
}
// User has opted out and declined to share their data
void AYourGameMode::OnUserOptedOutOfDataSharing()
{
USingularSDKBPLibrary::LimitDataSharing(true);
UE_LOG(LogTemp, Log, TEXT("Data sharing limited"));
}
// Example: Set based on user preference
void AYourGameMode::HandlePrivacyConsent(bool bUserConsented)
{
// Pass inverse: false = opted in, true = opted out
USingularSDKBPLibrary::LimitDataSharing(!bUserConsented);
UE_LOG(LogTemp, Log, TEXT("Data sharing: %s"),
bUserConsented ? TEXT("Enabled") : TEXT("Limited"));
}
如何使用:
Singular 在用户隐私回邮中使用此设置,并将其传递给需要遵守法规的合作伙伴。
GDPR 合规方法
管理用户跟踪同意和控制SDK功能,以符合GDPR(通用数据保护条例)和其他隐私法规。
跟踪同意管理
跟踪同意
通过向 Singular 服务器发送 GDPR 选入事件,记录用户对跟踪的明确同意。
方法签名:
static void TrackingOptIn()
何时使用:
- GDPR 合规性:当用户明确同意在受 GDPR 监管的地区进行跟踪时调用
- 同意记录:在 Singular 系统中将用户标记为已提供 GDPR 同意
- 默认行为:如果没有此调用,SDK 会继续跟踪,但不会明确记录同意信息
// User accepted tracking consent
void AGDPRManager::OnUserAcceptedTracking()
{
USingularSDKBPLibrary::TrackingOptIn();
UE_LOG(LogTemp, Log, TEXT("User opted in to tracking"));
}
// Example: Call after consent dialog
void AGDPRManager::ShowGDPRConsentDialog()
{
// Your consent dialog UI logic here
// ...
// If user accepts:
OnUserAcceptedTracking();
}
跟踪控制方法
停止所有跟踪
完全禁用当前用户在此设备上的所有 SDK 跟踪活动。
方法签名:
static void StopAllTracking()
严重警告:此方法会永久禁用 SDK,直到调用ResumeAllTracking() 。禁用状态会在应用程序重启时持续存在,只能通过编程方式逆转。
行为:
- 立即生效:立即停止所有跟踪、事件报告和数据收集功能
- 持续状态:即使在应用程序关闭和重新打开后也会保持禁用状态
-
无法自动重置:必须明确调用
ResumeAllTracking()才能重新启用
// User declined all tracking
void ATrackingController::OnUserDeclinedTracking()
{
USingularSDKBPLibrary::StopAllTracking();
UE_LOG(LogTemp, Log, TEXT("All tracking stopped"));
// Optionally store preference
SaveBoolToConfig(TEXT("tracking_enabled"), false);
}
// Example: Handle user opt-out from settings menu
void ATrackingController::HandlePrivacySettingsChange(bool bTrackingEnabled)
{
if (!bTrackingEnabled)
{
USingularSDKBPLibrary::StopAllTracking();
UE_LOG(LogTemp, Log, TEXT("Privacy settings: Tracking disabled"));
}
}
恢复所有跟踪
在使用StopAllTracking() 停止跟踪后重新启用跟踪。
方法签名:
static void ResumeAllTracking()
使用案例:
- 同意更改:用户更改隐私偏好并选择恢复跟踪
- 隐私设置:用户通过应用程序设置菜单更新同意
- 地区合规性:当用户转移到非监管区域时重新启用跟踪功能
// User opted back in to tracking
void ATrackingController::OnUserResumedTracking()
{
USingularSDKBPLibrary::ResumeAllTracking();
UE_LOG(LogTemp, Log, TEXT("Tracking resumed"));
// Optionally update stored preference
SaveBoolToConfig(TEXT("tracking_enabled"), true);
}
// Example: Handle consent update from settings
void ATrackingController::HandlePrivacySettingsChange(bool bTrackingEnabled)
{
if (bTrackingEnabled)
{
USingularSDKBPLibrary::ResumeAllTracking();
UE_LOG(LogTemp, Log, TEXT("Privacy settings: Tracking enabled"));
}
}
IsAllTrackingStopped
检查当前用户是否已禁用跟踪功能。
方法签名:
static bool IsAllTrackingStopped()
返回 返回 返回 返回值值值值
-
true:当前已通过
StopAllTracking()停止跟踪 - false:跟踪处于活动状态(从未停止或恢复
// Check current tracking status on startup
void APrivacySettingsUI::BeginPlay()
{
Super::BeginPlay();
UpdatePrivacyUI();
}
// Check current tracking status
bool APrivacySettingsUI::IsTrackingEnabled()
{
return !USingularSDKBPLibrary::IsAllTrackingStopped();
}
// Example: Display privacy status in settings
FString APrivacySettingsUI::GetPrivacyStatusText()
{
if (USingularSDKBPLibrary::IsAllTrackingStopped())
{
return TEXT("Tracking: Disabled");
}
else
{
return TEXT("Tracking: Enabled");
}
}
// Example: Sync UI with tracking state
void APrivacySettingsUI::UpdatePrivacyUI()
{
bool bIsStopped = USingularSDKBPLibrary::IsAllTrackingStopped();
if (TrackingToggle != nullptr)
{
TrackingToggle->SetIsChecked(!bIsStopped);
}
if (StatusText != nullptr)
{
FString StatusString = bIsStopped ? TEXT("Stopped") : TEXT("Active");
StatusText->SetText(FText::FromString(
FString::Printf(TEXT("Current tracking state: %s"), *StatusString)
));
}
UE_LOG(LogTemp, Log, TEXT("Current tracking state: %s"),
bIsStopped ? TEXT("Stopped") : TEXT("Active"));
}
// Handle toggle change from UI
void APrivacySettingsUI::OnTrackingToggleChanged(bool bEnabled)
{
if (bEnabled)
{
USingularSDKBPLibrary::ResumeAllTracking();
}
else
{
USingularSDKBPLibrary::StopAllTracking();
}
UpdatePrivacyUI();
}
儿童隐私保护
13 岁以下用户跟踪
通知 Singular 用户未满 13 周岁,以遵守 COPPA(儿童在线隐私保护法案)和其他儿童隐私法规。
方法签名:
static void TrackingUnder13()
合规要求:
- COPPA 合规性:收集美国 13 岁以下儿童数据的应用程序必须遵守
- 有年龄限制的内容:当用户在注册或年龄验证时表明自己未满 13 岁时使用
- 限制跟踪:限制数据收集,以遵守儿童隐私保护法
// User identified as under 13
void ACOPPAManager::OnUserUnder13()
{
USingularSDKBPLibrary::TrackingUnder13();
UE_LOG(LogTemp, Log, TEXT("COPPA mode enabled for user under 13"));
}
// Example: Call after age verification
void ACOPPAManager::OnAgeVerified(int UserAge)
{
if (UserAge < 13)
{
USingularSDKBPLibrary::TrackingUnder13();
UE_LOG(LogTemp, Log, TEXT("COPPA restrictions applied"));
// Also limit data sharing for children
USingularSDKBPLibrary::LimitDataSharing(true);
}
}
// Example: Age gate implementation
void AAgeGateWidget::OnAgeSubmitted(int UserAge)
{
if (UserAge < 13)
{
// Apply COPPA protections
USingularSDKBPLibrary::TrackingUnder13();
USingularSDKBPLibrary::LimitDataSharing(true);
UE_LOG(LogTemp, Warning, TEXT("Child user detected - privacy protections enabled"));
// Show age-appropriate content
ShowChildSafeContent();
}
else
{
// Standard tracking for users 13+
UE_LOG(LogTemp, Log, TEXT("Adult user - standard tracking enabled"));
InitializeStandardTracking();
}
}
重要提示:在确定用户未满 13 周岁后尽早调用此方法,最好是在应用程序初始化期间或年龄验证后立即调用。这样可确保所有后续跟踪都遵守儿童隐私保护法规。
实施最佳实践
完整隐私管理示例
实施全面的隐私控制,尊重用户偏好并遵守相关法规。
// ComprehensivePrivacyManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ComprehensivePrivacyManager.generated.h"
UCLASS()
class YOURGAME_API AComprehensivePrivacyManager : public AActor
{
GENERATED_BODY()
public:
AComprehensivePrivacyManager();
protected:
virtual void BeginPlay() override;
public:
// Initialize privacy settings on app startup
UFUNCTION(BlueprintCallable, Category = "Privacy")
void InitializePrivacySettings();
// User accepts tracking via consent dialog
UFUNCTION(BlueprintCallable, Category = "Privacy")
void OnUserAcceptedTracking();
// User declines tracking
UFUNCTION(BlueprintCallable, Category = "Privacy")
void OnUserDeclinedTracking();
// User updates data sharing preference
UFUNCTION(BlueprintCallable, Category = "Privacy")
void SetDataSharingEnabled(bool bEnabled);
// Check if tracking is currently enabled
UFUNCTION(BlueprintCallable, Category = "Privacy")
bool IsTrackingEnabled();
// Get current privacy status as readable text
UFUNCTION(BlueprintCallable, Category = "Privacy")
FString GetPrivacyStatus();
private:
// Helper methods for config storage
bool GetUserConsent();
void SaveUserConsent(bool bConsent);
bool GetDataSharingPreference();
void SaveDataSharingPreference(bool bEnabled);
// Config keys
static const FString PREF_USER_CONSENT;
static const FString PREF_DATA_SHARING;
};
// ComprehensivePrivacyManager.cpp
#include "ComprehensivePrivacyManager.h"
#include "SingularSDKBPLibrary.h"
#include "Kismet/GameplayStatics.h"
const FString AComprehensivePrivacyManager::PREF_USER_CONSENT = TEXT("privacy_user_consent");
const FString AComprehensivePrivacyManager::PREF_DATA_SHARING = TEXT("privacy_data_sharing");
AComprehensivePrivacyManager::AComprehensivePrivacyManager()
{
PrimaryActorTick.bCanEverTick = false;
}
void AComprehensivePrivacyManager::BeginPlay()
{
Super::BeginPlay();
// Initialize privacy settings on app start
InitializePrivacySettings();
}
void AComprehensivePrivacyManager::InitializePrivacySettings()
{
bool bHasUserConsent = GetUserConsent();
bool bAllowDataSharing = GetDataSharingPreference();
// Apply stored tracking preference
if (bHasUserConsent)
{
USingularSDKBPLibrary::TrackingOptIn();
USingularSDKBPLibrary::ResumeAllTracking();
UE_LOG(LogTemp, Log, TEXT("Privacy initialized: Tracking enabled with consent"));
}
else
{
USingularSDKBPLibrary::StopAllTracking();
UE_LOG(LogTemp, Log, TEXT("Privacy initialized: Tracking disabled"));
}
// Set data sharing preference (inverse logic)
USingularSDKBPLibrary::LimitDataSharing(!bAllowDataSharing);
UE_LOG(LogTemp, Log, TEXT("Privacy initialized: consent=%s, sharing=%s"),
bHasUserConsent ? TEXT("true") : TEXT("false"),
bAllowDataSharing ? TEXT("true") : TEXT("false"));
}
void AComprehensivePrivacyManager::OnUserAcceptedTracking()
{
SaveUserConsent(true);
USingularSDKBPLibrary::TrackingOptIn();
USingularSDKBPLibrary::ResumeAllTracking();
UE_LOG(LogTemp, Log, TEXT("User accepted tracking"));
}
void AComprehensivePrivacyManager::OnUserDeclinedTracking()
{
SaveUserConsent(false);
USingularSDKBPLibrary::StopAllTracking();
UE_LOG(LogTemp, Log, TEXT("User declined tracking"));
}
void AComprehensivePrivacyManager::SetDataSharingEnabled(bool bEnabled)
{
SaveDataSharingPreference(bEnabled);
// Note: LimitDataSharing uses inverse logic
// false = data sharing enabled, true = data sharing limited
USingularSDKBPLibrary::LimitDataSharing(!bEnabled);
UE_LOG(LogTemp, Log, TEXT("Data sharing: %s"),
bEnabled ? TEXT("Enabled") : TEXT("Limited"));
}
bool AComprehensivePrivacyManager::IsTrackingEnabled()
{
return !USingularSDKBPLibrary::IsAllTrackingStopped();
}
FString AComprehensivePrivacyManager::GetPrivacyStatus()
{
bool bIsEnabled = !USingularSDKBPLibrary::IsAllTrackingStopped();
bool bDataSharingEnabled = GetDataSharingPreference();
return FString::Printf(TEXT("Tracking: %s\nData Sharing: %s"),
bIsEnabled ? TEXT("Enabled") : TEXT("Disabled"),
bDataSharingEnabled ? TEXT("Enabled") : TEXT("Limited"));
}
// Private helper methods for config storage
bool AComprehensivePrivacyManager::GetUserConsent()
{
// Implement your config storage retrieval here
// Example using GameInstance or SaveGame system
return false; // Default to no consent
}
void AComprehensivePrivacyManager::SaveUserConsent(bool bConsent)
{
// Implement your config storage here
// Example using GameInstance or SaveGame system
}
bool AComprehensivePrivacyManager::GetDataSharingPreference()
{
// Implement your config storage retrieval here
return false; // Default to limited sharing
}
void AComprehensivePrivacyManager::SaveDataSharingPreference(bool bEnabled)
{
// Implement your config storage here
}
最佳实践:
- 持久存储:使用虚幻引擎的 SaveGame 系统或自定义配置文件保存用户首选项。
- 早期初始化:尽可能在SDK初始化之前的BeginPlay()过程中应用隐私设置
-
UI 同步:使用
IsAllTrackingStopped()保持设置 UI 与实际 SDK 状态同步 - 清晰交流:在应用设置中提供清晰、易用的隐私控制
-
反向逻辑:请记住,
LimitDataSharing(false)意味着启用数据共享,而true则意味着限制数据共享 - 合规文档:保留用户何时以及如何提供或撤销同意的记录
方法参考摘要
| 方法 | 说明 | 何时使用 |
|---|---|---|
LimitDataSharing(bool)
|
根据用户同意控制第三方数据共享 | CCPA 合规性、用户隐私偏好 |
TrackingOptIn()
|
记录明确的 GDPR 跟踪同意 | 欧盟地区的 GDPR 合规性 |
StopAllTracking()
|
完全禁用 SDK 跟踪 | 用户拒绝所有跟踪同意 |
ResumeAllTracking()
|
停止后重新启用跟踪 | 用户更改同意重新选择 |
IsAllTrackingStopped()
|
检查当前跟踪状态 | 同步用户界面,操作前检查状态 |
TrackingUnder13()
|
启用 COPPA 儿童保护 | 用户被识别为 13 岁以下 |