app_info_utils 0.1.6
app_info_utils: ^0.1.6 copied to clipboard
Unified native app, device, locale, timezone, and identifier information for Flutter apps on iOS and Android.
app_info_utils #
This package has moved to
x_app_utils.New projects should use
x_app_utils. Existing projects can migrate by replacing the dependency and import:dependencies: x_app_utils: ^0.1.6import 'package:x_app_utils/x_app_utils.dart'; final info = XAppUtils.instance;
A Flutter plugin that exposes unified app, device, locale, timezone, and identifier information on iOS and Android.
The package keeps native values cached in memory and initializes itself on first use, so values can be read through synchronous getters in the rest of your app.
Features #
- App metadata: app name, package name, version, build number, installer store, install time, update time, and Android build signature.
- Device and system metadata: model, manufacturer/platform, OS version, device name, physical device flag, disk size, and memory size.
- Locale and timezone metadata: language code, ISO-3 language code, country code, ISO-3 country code, locale, timezone, and UTC offset.
- Identifiers: IDFA, IDFV, Android ID, Google advertising ID, App Set ID,
secure primary/secondary local IDs, and unified
advertisingId/deviceIdconvenience getters. - iOS ATT authorization helper for requesting IDFA access at the right moment in your app flow.
Installation #
dependencies:
app_info_utils: ^0.1.5
Then import the package:
import 'package:app_info_utils/app_info_utils.dart';
Usage #
For a complete Chinese integration guide, see doc/USAGE.md.
Read values from the shared instance:
final info = AppInfoUtils.instance;
final appName = info.appName;
final packageName = info.packageName;
final version = info.version;
final model = info.deviceModel;
final country = info.countryCode;
final timeZone = info.timeZone;
final deviceId = info.deviceId;
final primaryLocalId = info.primaryLocalId;
final secondaryLocalId = info.secondaryLocalId;
If native values have not been loaded yet, the first getter read starts loading them automatically and returns the documented fallback value for that read. Later reads return the cached native values.
AppInfoUtils.instance is the recommended entry point. AppInfoUtils() is
kept as a singleton factory for compatibility.
You may also initialize explicitly during app startup when you want to preload native values:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final initialized = await AppInfoUtils.instance.init();
if (!initialized) {
// Some native values or secure local ID persistence are unavailable.
// primaryLocalId and secondaryLocalId still have in-memory UUID fallbacks.
}
runApp(const MyApp());
}
init() returns true when native values were loaded and false when they
were unavailable. It does not throw for channel/native read failures.
If you must guarantee that native values are loaded before a local read, use:
final info = await AppInfoUtils.instance.ready;
final model = info.deviceModel;
Refreshing Values #
final refreshed = await AppInfoUtils.instance.refresh();
await AppInfoUtils.instance.refreshAdvertisingId();
await AppInfoUtils.instance.refreshDeviceId();
await AppInfoUtils.instance.resetLocalId();
The plugin also refreshes cached values when the app returns to the foreground.
Advertising IDs and Android privacy #
init() and foreground refreshes do not read advertising identifiers. Read the
Google advertising ID only when your app has obtained any required user consent:
await AppInfoUtils.instance.refreshAdvertisingId();
The package intentionally does not add Android's AD_ID permission to the host
app. If you use refreshAdvertisingId(), add it to the host application's
android/app/src/main/AndroidManifest.xml and complete the applicable Google
Play Data safety disclosure:
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
refreshDeviceId() reads Android's App Set ID on demand. Both calls return an
empty identifier when the relevant service, permission, or user setting makes
the value unavailable.
Secure Local IDs #
primaryLocalId and secondaryLocalId are UUID values generated independently
on each platform. Android stores them with Android KeyStore + RSA OAEP +
AES-GCM encrypted SharedPreferences. iOS stores them in Keychain with
kSecAttrAccessibleWhenUnlocked.
By default, storage keys use the Android package name or iOS bundle identifier. If the platform namespace is temporarily unavailable, provide a fallback namespace; when both namespaces are available on the same platform, values are synchronized so future reads stay consistent.
await AppInfoUtils.instance.init(
localIdStorageOptions: const LocalIdStorageOptions(
fallbackNamespace: 'my_app',
),
);
Manage either local ID through a single slot-based API:
final primary = await AppInfoUtils.instance.readLocalId();
final secondary = await AppInfoUtils.instance.readLocalId(
slot: LocalIdSlot.secondary,
);
await AppInfoUtils.instance.writeLocalId('custom-id');
final exists = await AppInfoUtils.instance.containsLocalId();
await AppInfoUtils.instance.deleteLocalId();
final newPrimary = await AppInfoUtils.instance.resetLocalId();
iOS IDFA and ATT #
init() never shows the ATT prompt. It only reads IDFA when tracking permission
has already been granted.
To request ATT authorization:
final result = await AppInfoUtils.instance.requestIdfaAuthorization();
if (result.isSuccess) {
final idfa = result.idfa;
} else {
final failure = result.failure;
}
Before calling requestIdfaAuthorization() in a real iOS app, add
NSUserTrackingUsageDescription to the host app's ios/Runner/Info.plist:
<key>NSUserTrackingUsageDescription</key>
<string>This identifier is used to provide more relevant content and advertising.</string>
Fallbacks #
String getters never return null. Unavailable values return '', except these
documented locale defaults:
| Getter | Default |
|---|---|
languageCode |
en |
languageCode3 |
eng |
countryCode |
US |
countryCode3 |
USA |
locale |
en_US |
Integer getters return 0, boolean getters return false, and list getters
return an empty list when native values are unavailable.
Disk sizes are bytes. RAM sizes are MiB; iOS reports 0 for
availableRamSize, because iOS has no supported system-wide available-memory
API.
Local-ID write, delete, and reset methods throw a StateError when the native
secure store cannot complete the requested change. This prevents an in-memory
value from being reported as persisted when it is not.
Publishing #
Before publishing from this directory, run:
flutter test
flutter analyze
flutter pub publish --dry-run