デバイスデータ取得ガイド
正確な S2S API アトリビューションとキャンペーン測定に必要な、プラットフォーム固有のデバイス識別子とパラメータを取得するための包括的なガイド。
必須のデバイス識別子: Singular では、正確なアトリビューションのために、すべての API リクエストで特定のデバイス識別子が必要です。
モバイルプラットフォーム:
- Android(Google Play): Google Advertising ID(GAID/AIFA)と App Set ID(ASID)
- Android(Amazon): Fire デバイス向けの Amazon Advertising ID(AMID)
- Android(中国 OEM): Google Play 開発者サービスがないデバイス向けの Open Advertising ID(OAID)
- Android(フォールバック): 他に利用できる識別子がない場合にのみ使用する Android ID(ANDI)
- iOS: ベンダー用識別子(IDFV)と、利用可能な場合は広告主用識別子(IDFA)
デバイスパラメータ: モバイルプラットフォームで必須の、ロケール、デバイスメーカー、デバイスモデル、ビルドバージョン
以下のコード例は、各プラットフォームと識別子タイプの取得方法を示します。
サンプルアプリケーション
リファレンス実装
デバイスデータ取得パターンを示す、iOS と Android の完全な動作サンプル。
Singular Device ID(SDID)
アプリに Singular SDK が含まれている場合(ハイブリッドインテグレーション)、プラットフォーム固有の識別子を収集する代わりに、SDK から Singular Device ID(SDID)を取得し、
sdid
パラメータとして送信します。SDK は SDID を自動的に生成し、解決します。各 SDK で SDID を取得する方法については、以下の SDK インテグレーションガイドを参照してください:
デバイスに SDK がない純粋な server-to-server インテグレーションの場合は、SDID として使用する UUIDv4 をクライアント側で生成するか、以下に記載するプラットフォーム固有の識別子を引き続き使用します。
iOS デバイス識別子
iOS デバイスでは、正確なアトリビューションのために、IDFV(常時)と IDFA(ユーザーがトラッキング許可を付与した場合)、および ATT 認可ステータスが必要です。
必須の iOS 識別子
識別子の要件:
- IDFV: トラッキング許可の有無にかかわらず、すべての S2S リクエストで必須
- IDFA: ユーザーが App Tracking Transparency の同意を付与した場合は提供する必要があります
- ATT ステータス: すべてのリクエストで必須の認可ステータスコード(0〜3)
実装ガイド
広告主用識別子(IDFA)
広告主用識別子(IDFA)を使用すると、広告主はユーザーのアクション(広告クリック、アプリインストール)を特定のキャンペーンに追跡・アトリビュートでき、精密なターゲティングと最適化が可能になります。
iOS 14.5 以降、アプリが IDFA にアクセスする前に、ユーザーは App Tracking Transparency(ATT)フレームワークを介してオプトインする必要があります。ユーザーの同意がない場合、IDFA はすべてゼロを返し、トラッキング機能が制限されます。
ベンダー用識別子(IDFV)
ベンダー用識別子(IDFV)は、Apple がデバイスに割り当てる一意の識別子で、ベンダー/デベロッパーごとに固有です。デバイス上の同じベンダーのすべてのアプリで一貫して同じ値になり、個人を特定することなくアプリ横断の行動トラッキングを可能にします。
実装手順:
- IDFA へのアクセスを試みる前に、ATT プロンプトを表示して処理しておきます
- IDFA を取得し(許可されている場合)、API リクエスト用にサーバーへ渡します
- IDFV を取得し、API リクエスト用にサーバーへ渡します(常に必須)
- すべてのリクエストに ATT 認可ステータスを含めます
コード例
ATT 認可のリクエストと IDFA/IDFV の取得
#import <AdSupport/AdSupport.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <UIKit/UIKit.h>
- (void)retrieveIdentifiers {
// Request ATT authorization (iOS 14.5+)
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
dispatch_async(dispatch_get_main_queue(), ^{
switch (status) {
case ATTrackingManagerAuthorizationStatusAuthorized: {
// ATT authorized, retrieve IDFA
NSUUID *idfa = [[ASIdentifierManager sharedManager] advertisingIdentifier];
NSLog(@"IDFA: %@", [idfa UUIDString]);
NSLog(@"ATT Status: %ld", (long)status); // Status = 3
break;
}
case ATTrackingManagerAuthorizationStatusDenied:
NSLog(@"ATT Status: Denied (%ld)", (long)status); // Status = 2
break;
case ATTrackingManagerAuthorizationStatusRestricted:
NSLog(@"ATT Status: Restricted (%ld)", (long)status); // Status = 1
break;
case ATTrackingManagerAuthorizationStatusNotDetermined:
NSLog(@"ATT Status: Not Determined (%ld)", (long)status); // Status = 0
break;
default:
NSLog(@"Unknown ATT status.");
break;
}
// Retrieve IDFV (always available)
NSUUID *idfv = [[UIDevice currentDevice] identifierForVendor];
if (idfv != nil) {
NSLog(@"IDFV: %@", [idfv UUIDString]);
} else {
NSLog(@"Unable to retrieve IDFV.");
}
});
}];
}
// Call the method to retrieve identifiers
[self retrieveIdentifiers];
import AdSupport
import AppTrackingTransparency
import UIKit
func retrieveIdentifiers() {
// Request ATT authorization (iOS 14.5+)
ATTrackingManager.requestTrackingAuthorization { status in
DispatchQueue.main.async {
switch status {
case .authorized:
// ATT authorized, retrieve IDFA
let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
print("IDFA: \(idfa)")
print("ATT Status: \(status.rawValue)") // Status = 3
case .denied:
print("ATT Status: Denied (\(status.rawValue))") // Status = 2
case .restricted:
print("ATT Status: Restricted (\(status.rawValue))") // Status = 1
case .notDetermined:
print("ATT Status: Not Determined (\(status.rawValue))") // Status = 0
@unknown default:
print("Unknown ATT status.")
}
// Retrieve IDFV (always available)
if let idfv = UIDevice.current.identifierForVendor?.uuidString {
print("IDFV: \(idfv)")
} else {
print("Unable to retrieve IDFV.")
}
}
}
}
// Call the function to retrieve identifiers
retrieveIdentifiers()
識別子の利用可否:
- IDFA: iOS 14.5 以降では ATT 認可が必要です。同意がない場合はすべてゼロを返します
- IDFV: 常に利用可能。すべての Singular API リクエストに含めます
- ATT ステータス値: 0=未決定、1=制限あり、2=拒否、3=許可
Android デバイス識別子(Google Play)
Google Play 開発者サービスを搭載した Android デバイスでは、すべてのリクエストで App Set ID(ASID)が必要で、利用可能な場合は Google Advertising ID(GAID/AIFA)も必要です。
必須の Google Play 識別子
識別子の要件:
- ASID: Google Play デバイスのすべての S2S リクエストで必須
- AIFA/GAID: 利用可能な場合(オプトアウトされていない場合)は提供する必要があります
実装ガイド
Google 広告識別子(GAID)
Google 広告識別子(GAID)は、AIFA または Android Advertising ID(AAID)とも呼ばれ、Android デバイスに割り当てられる一意の、ユーザーがリセット可能な識別子です。プライバシーを維持しながら、広告主とデベロッパーがアプリ間でユーザーのアクションを追跡・アトリビュートし、キャンペーンのターゲティングと最適化を行うことを可能にします。
依存関係
お使いの
build.gradle
に必要な依存関係を追加します:
dependencies {
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}
権限
Android 12 / API レベル 31 以降をターゲットにする場合は、お使いの
AndroidManifest.xml
に権限を追加します:
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
使い方
AdIdUtils.getGoogleAdId(getApplicationContext());
実装
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
public class AdIdUtils {
public static void getGoogleAdId(Context context) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
try {
Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
String adId = adInfo.getId();
boolean isLimitAdTrackingEnabled = adInfo.isLimitAdTrackingEnabled();
Log.d("GoogleAdID", "Advertising ID: " + adId);
Log.d("GoogleAdID", "Limit Ad Tracking: " + isLimitAdTrackingEnabled);
} catch (Exception e) {
Log.e("GoogleAdID", "Error retrieving GAID", e);
}
}
});
}
}
依存関係
dependencies {
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}
権限
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
使い方
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycleScope.launch {
val googleAdId = AdIdUtils.getGoogleAdId(applicationContext)
Log.d("MainActivity", "Retrieved Google Ad ID: $googleAdId")
}
}
}
実装
import android.content.Context
import android.util.Log
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
object AdIdUtils {
suspend fun getGoogleAdId(context: Context): String? {
return withContext(Dispatchers.IO) {
try {
val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)
val adId = adInfo.id
val isLimitAdTrackingEnabled = adInfo.isLimitAdTrackingEnabled
Log.d("GoogleAdID", "Advertising ID: $adId")
Log.d("GoogleAdID", "Limit Ad Tracking: $isLimitAdTrackingEnabled")
adId
} catch (e: Exception) {
Log.e("GoogleAdID", "Error retrieving GAID", e)
null
}
}
}
}
App Set ID(ASID)
Android App Set ID は、同一デベロッパー向けにプライバシーに配慮したアプリ横断のトラッキングを提供します。分析や不正防止に役立ちますが、パーソナライズド広告には使用できません。
依存関係
dependencies {
implementation 'com.google.android.gms:play-services-appset:16.1.0'
}
使い方
AppSetIdUtils.getAppSetId(getApplicationContext());
実装
import android.content.Context;
import android.util.Log;
import com.google.android.gms.appset.AppSet;
import com.google.android.gms.appset.AppSetIdClient;
import com.google.android.gms.appset.AppSetIdInfo;
import com.google.android.gms.tasks.Task;
public class AppSetIdUtils {
public static void getAppSetId(Context context) {
AppSetIdClient client = AppSet.getClient(context);
Task task = client.getAppSetIdInfo();
task.addOnSuccessListener(info - {
String appSetId = info.getId();
int scope = info.getScope();
Log.d("AppSetID", "App Set ID: " + appSetId);
Log.d("AppSetID", "Scope: " + (scope == AppSetIdInfo.SCOPE_DEVELOPER ? "Developer" : "App"));
}).addOnFailureListener(e - {
Log.e("AppSetID", "Failed to retrieve App Set ID", e);
});
}
}
依存関係
dependencies {
implementation 'com.google.android.gms:play-services-appset:16.1.0'
}
使い方
AppSetIdUtils.getAppSetId(applicationContext)
実装
import android.content.Context
import android.util.Log
import com.google.android.gms.appset.AppSet
import com.google.android.gms.appset.AppSetIdClient
import com.google.android.gms.appset.AppSetIdInfo
object AppSetIdUtils {
fun getAppSetId(context: Context) {
val client: AppSetIdClient = AppSet.getClient(context)
val task = client.appSetIdInfo
task.addOnSuccessListener { info -
val appSetId: String = info.id
val scope: Int = info.scope
Log.d("AppSetID", "App Set ID: $appSetId")
Log.d("AppSetID", "Scope: ${if (scope == AppSetIdInfo.SCOPE_DEVELOPER) "Developer" else "App"}")
}.addOnFailureListener { exception -
Log.e("AppSetID", "Failed to retrieve App Set ID", exception)
}
}
}
Android デバイス識別子(Google Play 以外)
Google Play 開発者サービスがない Android デバイスでは、デバイスの製造元と配信方法に応じた代替識別子が必要です。
Amazon デバイス識別子
AMID: Google Play 開発者サービスがない Amazon Fire デバイスでは、Amazon Advertising ID を提供する必要があります。
Amazon ID(AMID)
Amazon Advertising Identifier は、Google Play 開発者サービスがない Amazon Fire デバイス上でユーザーがリセット可能な広告トラッキングを可能にし、ユーザーのプライバシーを維持しながらアトリビューションを実現します。
要件:
- Fire OS 5.1 以降が動作する Amazon Fire デバイスで機能します
- ユーザーの Limit Ad Tracking 設定を尊重します
- Fire OS 以外のデバイスでは利用できない場合があります
使い方
AdvertisingIdHelper.getAmazonAdvertisingId(getContentResolver());
実装
import android.content.ContentResolver;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
public class AdvertisingIdHelper {
public static void getAmazonAdvertisingId(ContentResolver contentResolver) {
String advertisingID = "";
boolean limitAdTracking = false;
try {
limitAdTracking = Settings.Secure.getInt(contentResolver, "limit_ad_tracking") != 0;
advertisingID = Settings.Secure.getString(contentResolver, "advertising_id");
Log.d("AdvertisingID", "Amazon Advertising ID: " + advertisingID);
Log.d("LimitAdTracking", "Limit Ad Tracking: " + limitAdTracking);
} catch (SettingNotFoundException e) {
Log.e("AdvertisingID", "Advertising ID not supported on this device", e);
}
}
}
使い方
AdvertisingIdHelper.getAmazonAdvertisingId(contentResolver)
実装
import android.content.ContentResolver
import android.provider.Settings
import android.util.Log
object AdvertisingIdHelper {
fun getAmazonAdvertisingId(contentResolver: ContentResolver) {
try {
val limitAdTracking = Settings.Secure.getInt(contentResolver, "limit_ad_tracking") != 0
val advertisingID = Settings.Secure.getString(contentResolver, "advertising_id")
Log.d("AdvertisingID", "Amazon Advertising ID: $advertisingID")
Log.d("LimitAdTracking", "Limit Ad Tracking: $limitAdTracking")
} catch (e: Settings.SettingNotFoundException) {
Log.e("AdvertisingID", "Advertising ID not supported on this device", e)
}
}
}
中国 OEM 識別子
OAID: Google Play 開発者サービスがない中国製デバイスでは、Open Advertising Identifier を提供する必要があります。
Open Advertising ID(OAID)
Open Advertising Identifier(OAID)は、中国で製造された Android デバイスにおける広告用の一意かつ匿名の識別子です。Google Play 開発者サービスが利用できないデバイス向けの GAID の代替として、Mobile Security Alliance(MSA)によって導入されました。
対応デバイス: Huawei、Xiaomi、OPPO、Vivo、およびその他の中国製 Android デバイス
アクセスは MSA SDK または Huawei Mobile Services(HMS)経由で行います。
依存関係
dependencies {
implementation 'com.bun.msa.sdk:msa:1.0.26'
}
実装
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.bun.msa.sdk.DeviceId;
import com.bun.msa.sdk.DeviceIdSupplier;
import com.bun.msa.sdk.IIdentifierListener;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "OAIDExample";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getOAID();
}
private void getOAID() {
try {
DeviceId deviceId = new DeviceId(this);
deviceId.getDeviceIds(new IIdentifierListener() {
@Override
public void onSupport(boolean isSupport, DeviceIdSupplier supplier) {
if (isSupport && supplier != null) {
String oaid = supplier.getOAID();
Log.d(TAG, "OAID: " + oaid);
} else {
Log.e(TAG, "OAID not supported on this device");
}
}
});
} catch (Exception e) {
Log.e(TAG, "Error retrieving OAID", e);
}
}
}
依存関係
dependencies {
implementation 'com.bun.msa.sdk:msa:1.0.26'
}
実装
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.bun.msa.sdk.DeviceId
import com.bun.msa.sdk.DeviceIdSupplier
import com.bun.msa.sdk.IIdentifierListener
class MainActivity : AppCompatActivity() {
companion object {
private const val TAG = "OAIDExample"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
getOAID()
}
private fun getOAID() {
try {
val deviceId = DeviceId(this)
deviceId.getDeviceIds(object : IIdentifierListener {
override fun onSupport(isSupport: Boolean, supplier: DeviceIdSupplier?) {
if (isSupport && supplier != null) {
val oaid = supplier.oAID
Log.d(TAG, "OAID: $oaid")
} else {
Log.e(TAG, "OAID not supported on this device")
}
}
})
} catch (e: Exception) {
Log.e(TAG, "Error retrieving OAID", e)
}
}
}
Android ID フォールバック
ANDI の制限: Android ID は、他に利用できる識別子がなく、かつアプリが Google Play ストア経由で配信されていない場合にのみ提供できます。Google Play のアプリでは禁止されています。
Android ID(ANDI)
Android ID は、デバイスの初回セットアップ時に生成される一意の 64 ビット識別子です。Android 8.0(Oreo)以降、アプリごと・ユーザーごとにスコープが分けられ、同じ署名鍵を共有しない限り、異なるアプリは異なる Android ID を受け取ります。
永続性: デバイスを初期化するか、OTA 更新後にアプリをアンインストール/再インストールしない限り、値は一定のままです。
import android.provider.Settings;
import android.content.Context;
String androidId = Settings.Secure.getString(
context.getContentResolver(),
Settings.Secure.ANDROID_ID
);
import android.provider.Settings
val androidId: String = Settings.Secure.getString(
contentResolver,
Settings.Secure.ANDROID_ID
)
Web およびクロスプラットフォーム識別子
Web アプリケーションおよびクロスプラットフォーム実装では、正確なアトリビューション追跡のために Singular Device ID(SDID)が必要です。
必須の Web 識別子
SDID: Web、PC、コンソール、CTV プラットフォームのすべての S2S リクエストで Singular Device ID が必要です。
Singular Web SDK デバイス ID
Singular Device ID(SDID)は、Web アプリケーションおよび非モバイルプラットフォームにおいて、一貫したセッション横断のトラッキングを提供します。
前提条件: SDID を取得する前に、Singular Web SDK を実装して初期化しておく必要があります。
使い方
// Retrieve SDID after Singular SDK initialization
const sdid = window.singularSdk.getSingularDeviceId();
console.log("Singular Device ID:", sdid);
実装に関する注意:
getSingularDeviceId()
は、Singular SDK が正常に初期化された後にのみ呼び出してください。初期化前に取得しようとすると null が返されます。
モバイルデバイスパラメータ
必須のデバイスパラメータは、モバイルプラットフォームでのアトリビューションと分析に不可欠なコンテキストを提供します。
必須パラメータ
モバイルプラットフォーム: iOS と Android のすべての S2S リクエストで、ロケール、デバイスメーカー、デバイスモデル、ビルドが必要です。
パラメータの取得
完全なデバイスプロファイリングのために、ロケール、製造元、モデル、ビルド情報を収集します。
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <sys/sysctl.h>
// Retrieve Locale
NSString *retrieveLocale() {
NSString *locale = [[NSLocale currentLocale] localeIdentifier];
NSLog(@"Locale: %@", locale);
return locale;
}
// Retrieve Manufacturer (always Apple for iOS)
NSString *retrieveManufacturer() {
return @"Apple";
}
// Retrieve Device Model
NSString *deviceModel() {
size_t bufferSize = 64;
char model[bufferSize];
int status = sysctlbyname("hw.machine", model, &bufferSize, NULL, 0);
if (status == 0) {
NSString *deviceModel = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];
NSLog(@"Device Model: %@", deviceModel);
return deviceModel;
} else {
NSLog(@"Unable to retrieve device model.");
return nil;
}
}
// Retrieve Build Version
NSString *buildVersion() {
size_t bufferSize = 64;
char build[bufferSize];
int status = sysctlbyname("kern.osversion", build, &bufferSize, NULL, 0);
if (status == 0) {
NSString *buildVersion = [NSString stringWithCString:build encoding:NSUTF8StringEncoding];
NSLog(@"Build Version: %@", buildVersion);
return buildVersion;
} else {
NSLog(@"Unable to retrieve build version.");
return nil;
}
}
import Foundation
import UIKit
// Retrieve Locale
func retrieveLocale() - String {
let locale = Locale.current.identifier
print("Locale: \(locale)")
return locale
}
// Retrieve Manufacturer (always Apple for iOS)
func retrieveManufacturer() - String {
return "Apple"
}
// Retrieve Device Model
func deviceModel() - String? {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
print("Device Model: \(identifier)")
return identifier
}
// Retrieve Build Version
func buildVersion() - String? {
var size: Int = 0
sysctlbyname("kern.osversion", nil, &size, nil, 0)
var build = [CChar](repeating: 0, count: size)
sysctlbyname("kern.osversion", &build, &size, nil, 0)
let buildVersion = String(cString: build)
print("Build Version: \(buildVersion)")
return buildVersion
}
import android.os.Build;
import java.util.Locale;
// Locale (lc parameter)
String locale = Locale.getDefault().toString();
// Device Make (ma parameter)
String deviceMake = Build.MANUFACTURER;
// Device Model (mo parameter)
String deviceModel = Build.MODEL;
// Build (bd parameter)
String build = "Build/" + Build.ID;
import android.os.Build
import java.util.Locale
// Locale (lc parameter)
val locale: String = Locale.getDefault().toString()
// Device Make (ma parameter)
val deviceMake: String = Build.MANUFACTURER
// Device Model (mo parameter)
val deviceModel: String = Build.MODEL
// Build (bd parameter)
val build: String = "Build/" + Build.ID
パラメータのマッピング:
- ロケール(lc): 言語と地域のコード(例: en_US、zh_CN)
- メーカー(ma): デバイスの製造元(Apple、Samsung、Xiaomi)
- モデル(mo): 具体的なデバイスモデル(iPhone14,2、SM-G991B)
- ビルド(bd): 「Build/」を接頭辞とする OS ビルドバージョン
タイムスタンプパラメータ
オプションのタイムスタンプパラメータは、デバイスのインストールおよび更新の状態を示します。これらは OS が報告する値で、デバイス上で収集され、SESSION リクエストで送信されます。
install_time の取得
install_time
は、アプリがデバイスに実際にインストールされた時刻を OS が報告する Unix タイムスタンプ(秒)です。Android では
PackageInfo.firstInstallTime
(ミリ秒)を読み取り、1000 で割ります。iOS にはインストール時刻の API がないため、標準的な近似として、アプリの Documents ディレクトリの作成日を使用します。
#import <Foundation/Foundation.h>
// install_time: creation date of the Documents directory (proxy)
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *docs = [[fm URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] firstObject];
NSDictionary *attrs = [fm attributesOfItemAtPath:docs.path error:nil];
NSDate *created = attrs[NSFileCreationDate];
long installTime = (long)[created timeIntervalSince1970];
NSLog(@"install_time: %ld", installTime);
import Foundation
// install_time: creation date of the Documents directory (proxy)
let docs = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask).first!
let attrs = try? FileManager.default.attributesOfItem(atPath: docs.path)
let created = attrs?[.creationDate] as? Date
let installTime = created.map { Int($0.timeIntervalSince1970) }
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
// install_time: PackageInfo.firstInstallTime is in milliseconds
long installTime = 0L;
try {
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);
installTime = info.firstInstallTime / 1000L; // seconds
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
import android.content.pm.PackageManager
// install_time: PackageInfo.firstInstallTime is in milliseconds
val installMillis = packageManager
.getPackageInfo(packageName, 0)
.firstInstallTime
val installTime = installMillis / 1000 // seconds
これはデバイスのインストール時刻であり、Singular のアトリビューションインストール時刻ではありません。アトリビューションでは、セッションタイムスタンプ(
utime
)が使用されます。これは初回セッション(
install=true
)のものです。
update_time の取得
update_time
は、アプリがデバイス上で最後に更新された時刻を OS が報告する Unix タイムスタンプ(秒)です。Android では
PackageInfo.lastUpdateTime
(ミリ秒)を読み取り、1000 で割ります。iOS には更新時刻の API がないため、標準的な近似として、更新のたびに書き換えられるアプリバンドルの実行ファイルの作成日を使用します。
#import <Foundation/Foundation.h>
// update_time: creation date of the app bundle executable (proxy)
NSString *execPath = [[NSBundle mainBundle] executablePath];
NSDictionary *attrs = [[NSFileManager defaultManager]
attributesOfItemAtPath:execPath error:nil];
NSDate *updated = attrs[NSFileCreationDate];
long updateTime = (long)[updated timeIntervalSince1970];
NSLog(@"update_time: %ld", updateTime);
import Foundation
// update_time: creation date of the app bundle executable (proxy)
let execPath = Bundle.main.executablePath!
let attrs = try? FileManager.default.attributesOfItem(atPath: execPath)
let updated = attrs?[.creationDate] as? Date
let updateTime = updated.map { Int($0.timeIntervalSince1970) }
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
// update_time: PackageInfo.lastUpdateTime is in milliseconds
long updateTime = 0L;
try {
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);
updateTime = info.lastUpdateTime / 1000L; // seconds
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
import android.content.pm.PackageManager
// update_time: PackageInfo.lastUpdateTime is in milliseconds
val updateMillis = packageManager
.getPackageInfo(packageName, 0)
.lastUpdateTime
val updateTime = updateMillis / 1000 // seconds
アプリが一度も更新されていないデバイスでは、これは
install_time
と等しくなります。これはアトリビューションのアクティビティではなく、アプリの更新を反映します。