2026-06-02 19:01:08 +08:00
|
|
|
import 'dart:io';
|
|
|
|
|
|
2026-06-05 16:08:28 +08:00
|
|
|
import 'package:adjust_sdk/adjust.dart';
|
2026-06-02 19:01:08 +08:00
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
|
import 'package:uuid/uuid.dart';
|
|
|
|
|
import 'package:android_id/android_id.dart';
|
|
|
|
|
import 'package:device_info_plus/device_info_plus.dart';
|
|
|
|
|
import 'package:flutter_vpn_detector/vpn_checker.dart';
|
|
|
|
|
import 'package:package_info_plus/package_info_plus.dart';
|
|
|
|
|
import 'package:play_install_referrer/play_install_referrer.dart';
|
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
|
|
|
|
|
|
class DeviceInfo {
|
|
|
|
|
static const String _spInstallReferrer = "installReferrer";
|
|
|
|
|
static const int defaultTimeout = 1000;
|
|
|
|
|
static const int defaultMaxTimeout = 2000;
|
|
|
|
|
DeviceInfo._();
|
|
|
|
|
static final DeviceInfo I = DeviceInfo._();
|
|
|
|
|
Future<Map<String, dynamic>> deviceInfo({
|
|
|
|
|
int adidTimeout = -1,
|
|
|
|
|
bool includeInstallReferrer = false,
|
2026-06-05 16:08:28 +08:00
|
|
|
bool includeAdjust = true,
|
2026-06-02 19:01:08 +08:00
|
|
|
}) async {
|
|
|
|
|
final Map<String, dynamic> json = {};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
adidTimeout = getTimeOut(adidTimeout);
|
|
|
|
|
final packageInfo = await PackageInfo.fromPlatform();
|
|
|
|
|
final devicePlugin = DeviceInfoPlugin();
|
|
|
|
|
|
|
|
|
|
final locale = PlatformDispatcher.instance.locale;
|
|
|
|
|
bool isActive = await VpnChecker.isVpnActive();
|
|
|
|
|
json["isVpn"] = isActive;
|
|
|
|
|
json["country"] = locale.countryCode;
|
|
|
|
|
json["language"] = locale.languageCode;
|
|
|
|
|
json["packageName"] = packageInfo.packageName;
|
|
|
|
|
json["versionName"] = packageInfo.version;
|
|
|
|
|
json["versionCode"] = packageInfo.buildNumber;
|
|
|
|
|
if (Platform.isAndroid) {
|
|
|
|
|
final androidInfo = await devicePlugin.androidInfo;
|
|
|
|
|
|
|
|
|
|
json["osVersion"] = androidInfo.version.release;
|
|
|
|
|
json["sdkInt"] = androidInfo.version.sdkInt.toString();
|
|
|
|
|
json["brand"] = androidInfo.brand;
|
|
|
|
|
json["model"] = androidInfo.model;
|
|
|
|
|
json["device"] = androidInfo.device;
|
|
|
|
|
json["androidId"] = await getAndroidId();
|
|
|
|
|
} else if (Platform.isIOS) {
|
|
|
|
|
final iosInfo = await devicePlugin.iosInfo;
|
|
|
|
|
json["osVersion"] = iosInfo.systemVersion;
|
|
|
|
|
json["model"] = iosInfo.model;
|
|
|
|
|
json["device"] = iosInfo.modelName;
|
|
|
|
|
json["androidId"] = iosInfo.identifierForVendor;
|
2026-06-05 16:08:28 +08:00
|
|
|
json['idfv'] = iosInfo.identifierForVendor;
|
|
|
|
|
try {
|
|
|
|
|
json['idfa'] = await Adjust.getIdfa();
|
|
|
|
|
if (includeAdjust) {
|
|
|
|
|
json['adjustAdId'] = await Adjust.getAdid();
|
|
|
|
|
final adjustAttribution = await Adjust.getAttribution();
|
|
|
|
|
json['adjustAttribution'] = adjustAttribution.jsonResponse;
|
|
|
|
|
json["clickLable"] = adjustAttribution.clickLabel;
|
|
|
|
|
}
|
|
|
|
|
} catch (_) {}
|
|
|
|
|
|
2026-06-02 19:01:08 +08:00
|
|
|
debugPrint("$iosInfo");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (includeInstallReferrer) {
|
|
|
|
|
final installReferrer = await getInstallReferrer(timeout: adidTimeout);
|
|
|
|
|
if (installReferrer != null && installReferrer.isNotEmpty) {
|
|
|
|
|
json["installReferrer"] = installReferrer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
debugPrint("[DeviceInfo] load adjust/referrer failed: $e");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return json;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<String?> getInstallReferrer({int timeout = 2000}) async {
|
|
|
|
|
try {
|
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
|
|
|
final cachedReferrer = prefs.getString(_spInstallReferrer);
|
|
|
|
|
if (cachedReferrer != null && cachedReferrer.isNotEmpty) {
|
|
|
|
|
return cachedReferrer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final referrerDetails = await PlayInstallReferrer.installReferrer.timeout(
|
|
|
|
|
Duration(milliseconds: timeout),
|
|
|
|
|
);
|
|
|
|
|
final referrer = referrerDetails.installReferrer;
|
|
|
|
|
|
|
|
|
|
if (referrer != null && referrer.isNotEmpty) {
|
|
|
|
|
await prefs.setString(_spInstallReferrer, referrer);
|
|
|
|
|
}
|
|
|
|
|
return referrer;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
debugPrint("[DeviceInfo] get install referrer failed: $e");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int getTimeOut(int timeout) {
|
|
|
|
|
if (timeout <= 0) {
|
|
|
|
|
return defaultTimeout;
|
|
|
|
|
}
|
|
|
|
|
return timeout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<String> getAndroidId() async {
|
|
|
|
|
try {
|
|
|
|
|
AndroidId androidIdPlugin = AndroidId();
|
|
|
|
|
final androidId = await androidIdPlugin.getId();
|
|
|
|
|
return androidId ?? await createDeviceId();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
debugPrint("[DeviceInfo] get Android ID failed: $e");
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<String> createDeviceId() async {
|
|
|
|
|
const key = "createdDeviceId";
|
|
|
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
|
|
|
String? deviceId = prefs.getString(key);
|
|
|
|
|
if (deviceId != null && deviceId.isNotEmpty) {
|
|
|
|
|
return deviceId;
|
|
|
|
|
}
|
|
|
|
|
final uuid = const Uuid();
|
|
|
|
|
deviceId = uuid.v4();
|
|
|
|
|
deviceId = deviceId.replaceAll('-', '');
|
|
|
|
|
await prefs.setString(key, deviceId);
|
|
|
|
|
return deviceId;
|
|
|
|
|
}
|
|
|
|
|
}
|