web-dev-qa-db-fra.com

Android 10: IMEI n'est plus disponible sur l'API 29. Recherche d'alternatives

La fonctionnalité principale de l'application de notre client est de relayer fortement le suivi des appareils de ses clients, ils proposent des produits qui sont liés au téléphone spécifique (pas à son propriétaire). Cela a été possible en utilisant l'appareil imei, mais avec les changements de confidentialité dans Android 10, ils l'ont rendu inaccessible. ( https://developer.Android.com/about/versions/ 10/confidentialité/modifications ).

Android a une documentation sur l'identifiant à utiliser dans des cas d'utilisateurs spécifiques, mais ne correspond pas à notre cas car nous avons besoin qu'il soit unique, constant et lié à l'appareil (ou du moins difficile à changer). https://developer.Android.com/training/articles/user-data-ids . J'envisage Android ID d'être une solution possible, ou d'utiliser l'adresse mac en sachant qu'ils ne sont pas fiables à 100%.

Des pensées? recommandations? expériences? à ce stade, tout pourrait être une option

15
kvnnj.m_av

Je vous conseille de lire le blog officiel des meilleures pratiques de google pour voir ce que le cas d'utilisation correspond à vos spécifications: https://developer.Android.com/training/articles/user-data-ids.html

Pour moi, j'ai rencontré le même problème concernant l'unicité des identifiants Android et j'ai trouvé que la seule solution était d'utiliser l'API MediaDrm ( https://Android.googlesource.com/platform) /frameworks/base/+/Android-cts-4.4_r1/media/Java/Android/media/MediaDrm.Java#539 ) qui contient un identifiant d'appareil unique et peut survivre même lors de la réinitialisation d'usine et n'a pas besoin toute autorisation supplémentaire sur votre fichier manifeste.

Voici le couple de code, comment pouvons-nous récupérer l'identifiant unique sur Android 10:

import Android.media.MediaDrm
import Java.security.MessageDigest
import Java.util.*

object UniqueDeviceID {

    /**
     * UUID for the Widevine DRM scheme.
     * <p>
     * Widevine is supported on Android devices running Android 4.3 (API Level 18) and up.
     */
    fun getUniqueId(): String? {

        val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)
        var wvDrm: MediaDrm? = null
        try {
            wvDrm = MediaDrm(WIDEVINE_UUID)
            val widevineId = wvDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID)
            val md = MessageDigest.getInstance("SHA-256")
            md.update(widevineId)
            return  md.digest().toHexString()
        } catch (e: Exception) {
            //WIDEVINE is not available
            return null
        } finally {
            if (AndroidPlatformUtils.isAndroidTargetPieAndHigher()) {
                wvDrm?.close()
            } else {
                wvDrm?.release()
            }
        }
    }


    fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
}

Pour Java utilisateurs intéressés par la solution par @Sofien, j'ai:

  1. Converti le code de @ Sofien en Java et encore simplifié;
  2. Testé intensivement sur plus d'appareils et de versions de système d'exploitation, même si le cas qui nous intéresse est Android 10 (API 29).

1. Code et discussion

@Nullable
String getUniqueID() {
   UUID wideVineUuid = new UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L);
   try {
      MediaDrm wvDrm = new MediaDrm(wideVineUuid);
      byte[] wideVineId = wvDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID);
      return Arrays.toString(wideVineId);
   } catch (Exception e) {
      // Inspect exception
      return null;
   }
   // Close resources with close() or release() depending on platform API
   // Use ARM on Android P platform or higher, where MediaDrm has the close() method
}

Il y a deux différences clés par rapport à t. @ Code de Sophien.

  • Je n'utilise pas le MessageDigest, ce qui donne un code plus simple. De plus, la méthode MessageDigest.update() applique la fonction de hachage SHA-256 À son argument, ce qui introduit une probabilité extrêmement faible de perdre l'unicité UUID. Le seul inconvénient de ne pas hacher l'UUID est que vous n'avez pas d'UUID de longueur fixe, ce qui ne m'importe pas dans mon application.
  • Au lieu de la fonction Kotlin toHexString (qui n'a pas d'équivalent sur une ligne en Java) j'utilise Arrays.toString. Ce choix est sûr car (A) Il ne lance pas Exception et (B) il conserve une correspondance biunivoque entre la wideVineId et sa représentation String. Si vous préférez vous en tenir à la conversion hexadécimale, la bibliothèque Apache Commons Codec propose une solution sur une seule ligne, voir cette réponse .

Bien sûr, ces changements entraînent un UUID différent, inutile de dire que d'autres choix sont possibles. Notez également qu'un UUID généré avec Arrays.toString Prend la forme

[92, -72, 76, -100, 26, -86, 121, -57, 81, -83, -81, -26, -26, 3, -49, 97, -24, -86, 17, -106, 25, 102, 55, 37, 47, -5, 33, -78, 34, 121, -58, 109]

Donc, si vous ne voulez pas de caractères spéciaux dans votre UUID, vous pouvez les supprimer avec String.replaceAll().

2. Tests

J'ai testé la persistance de l'UUID

  • sur la réinstallation
  • sur la réinstallation ET le redémarrage

sur les combinaisons appareil/système d'exploitation suivantes:

  • Samsung Galaxy S10/API 29
  • Samsung Galaxy S9/API 29
  • Huawei Nexus 6P/API 27 (testé également réinitialisé aux paramètres d'usine)
  • Asus ZenFone 2/API 23
  • Samsung Galaxy J5/API 23
  • LG Nexus 5/API 23
  • LG K4/API 22
  • Samsung Galaxy J3/API 22
  • Samsung Galaxy S4/API 21

Dans tous les tests, le targetSdkVersion est 29.

1
Massimo Frittelli
  1. Vous pouvez accéder à Android id d'appareil par le service gms. Voir l'exemple ci-dessous,
private DeviceInfoProvider mDeviceInfo = new DeviceInfoProvider(Context)
String mDeviceId = DeviceInfoProvider.getDeviceId(Context);
Log.d("DEVICE_ID" , mDeviceId);
  1. Lors du premier démarrage d'un périphérique, une valeur aléatoire est générée et stockée. Cette valeur est disponible via Settings.Secure.Android_ID. Il s'agit d'un nombre 64 bits qui doit rester constant pendant toute la durée de vie d'un appareil. Android_ID semble être un bon choix pour un identifiant d'appareil unique, car il est disponible pour les smartphones et les tablettes. Pour récupérer la valeur, vous pouvez utiliser le code suivant,
String androidId = Settings.Secure.getString(getContentResolver(),
                                             Settings.Secure.Android_ID);

Cependant, la valeur peut changer si une réinitialisation d'usine est effectuée sur l'appareil. Il existe également un bug connu avec un combiné populaire d'un fabricant où chaque instance a le même Android_ID. De toute évidence, la solution n'est pas fiable à 100%.

  1. Utilisation UUID. Comme la plupart des applications ont besoin d'identifier une installation particulière et non un périphérique physique, une bonne solution pour obtenir l'identifiant unique d'un utilisateur s'il souhaite utiliser la classe UUID. La solution suivante a été présentée par Reto Meier de Google dans un E/S Google présentation,
SharedPreferences sharedPrefs = context.getSharedPreferences(
PREF_UNIQUE_ID, Context.MODE_PRIVATE);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
1
Kiran Maniya