# Unique Identifier
[](https://pub.flutter-io.cn/packages/unique_identifier_3)
A Flutter plugin to retrieve the `ANDROID_ID` for Android devices and `identifierForVendor` for iOS devices. This unique identifier allows you to track devices in a secure and platform-compliant way.
## Installation
To add this package to your project, update the dependencies in your `pubspec.yaml` file:
```yaml
dependencies:
  unique_identifier_3: ^0.0.1
Import the Package
import 'package:unique_identifier_3/unique_identifier_3.dart';
Usage
Example Code
The following example demonstrates how to retrieve a unique identifier for the device and display it in a Flutter app:
import 'package:flutter/material.dart';
import 'package:unique_identifier_3/unique_identifier_3.dart';
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
  String _identifier = 'Unknown';
  @override
  void initState() {
    super.initState();
    initUniqueIdentifier();
  }
  // Method to initialize and retrieve the unique identifier
  Future<void> initUniqueIdentifier() async {
    String identifier;
    try {
      identifier = await UniqueIdentifier.serial;
    } on PlatformException {
      identifier = 'Failed to get Unique Identifier';
    }
    if (!mounted) return;
    setState(() {
      _identifier = identifier;
    });
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Unique Identifier Example'),
        ),
        body: Center(
          child: Text('Device ID: $_identifier\n'),
        ),
      ),
    );
  }
}
iOS App Tracking Transparency
If your app uses tracking on iOS, ensure that you request App Tracking Transparency (ATT) permission from users. The following code includes permission handling and a custom dialog prompt for iOS:
import 'package:flutter/material.dart';
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
Future<void> initTrackingTransparency(BuildContext context) async {
  final status = await AppTrackingTransparency.trackingAuthorizationStatus;
  if (status == TrackingStatus.notDetermined || status == TrackingStatus.denied) {
    // Show a custom dialog before the system's tracking dialog
    await showCustomTrackingDialog(
      context,
      'We use tracking to enhance your experience and provide personalized content and ads. '
      'Please consider enabling tracking for improved service.',
    );
    // Delay to allow the dialog animation to complete
    await Future.delayed(const Duration(milliseconds: 1000));
    // Request ATT permission
    final newStatus = await AppTrackingTransparency.requestTrackingAuthorization();
    if (newStatus == TrackingStatus.notDetermined || newStatus == TrackingStatus.denied) {
      await showSettingsDialog(
        context,
        'To enhance your experience, please enable tracking in Settings > Privacy & Security > Tracking.',
      );
    }
  }
  // Retrieve the advertising identifier
  final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
  if (uuid == '00000000-0000-0000-0000-000000000000') {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text("Unable to track your device")),
    );
  }
}
// Custom dialog to explain tracking
Future<void> showCustomTrackingDialog(BuildContext context, String message) async {
  return showDialog<void>(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('Attention'),
      content: Text(message),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('Continue'),
        ),
      ],
    ),
  );
}
// Settings dialog to guide the user to enable tracking
Future<void> showSettingsDialog(BuildContext context, String message) async {
  return showDialog<void>(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('Settings Required'),
      content: Text(message),
      actions: [
        TextButton(
          onPressed: () async {
            const url = 'app-settings:';
            if (await canLaunchUrlString(url)) {
              await launchUrlString(url);
            } else {
              debugPrint('Could not launch $url');
            }
            Navigator.pop(context);
          },
          child: const Text('Settings'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('Not Now'),
        ),
      ],
    ),
  );
}
Bugs & Feature Requests
If you encounter any issues or have feature requests, please open an issue on GitHub. Contributions through pull requests are also welcome!
Additional Information
Platform-Specific Behavior
- Android (8.0 and above): ANDROID_IDis a unique, 64-bit hexadecimal string associated with each combination of app-signing key, user, and device. The value may change after a factory reset or if the app-signing key changes.
- iOS: The identifierForVendor(IDFV) is unique per vendor and can change if all apps from a vendor are uninstalled from a device and reinstalled.
For more details, see the official Android 8.0 Behavior Changes documentation.
License
This project is licensed under the MIT License.