Android 獲取設備惟一標識

一. 先簡單總結一下比較常見的幾個解決方案的弊端:

1. IMEI

Android 10 中官方明確說明第三方應用沒法獲取到IMEI碼Android 10 中的隱私權變動android

Android 10 如下的版本,須要申請READ_PHONE_STATE權限。markdown

2. Android ID

Android ID 不具備真正的惟一性app

ROOT、刷機、恢復出廠設置、不一樣簽名的應用等都會致使獲取的 Android ID 發生改變,dom

而且不一樣廠商定製的系統的BUG會致使不一樣的設備可能會產生相同的 Android ID。async

3. MAC地址

Android 10 中 MAC地址具備隨機化的特徵Android 10 中的隱私權變動—MAC地址oop

雖然目前大部分手機還不支持這個特性,可是隨着廠商的跟進,這個方案就會逐漸做廢ui

在上面這些設備自帶的標識不夠知足需求時,咱們就要採用另外的方法了。google

二. uuid + 本地文件,實現一個通用解決方案

1. 思路

啓動APP時,檢查並讀取根目錄下保存有uuid的文件,若沒有該文件,則視爲一臺新設備,建立文件並寫入uuid。spa

而且要確保卸載應用時,該文件不會被系統攜帶着刪除(這也是爲何要在根目錄下建立的緣由)。插件

2. 解決手機訪問SDK權限問題

Android 6 如下,添加權限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
複製代碼

Android 6 及其以上,則須要在此基礎上申請動態權限。

Android 10 及其以上,文件存儲機制修改爲了沙盒模式,即應用只能訪問本身沙盒下的文件和公共媒體文件。

「得益」於沙盒機制,應用建立的文件屬於本身的沙盒,那麼當應用卸載時,也會隨之刪除。

目前能夠添加如下一行代碼解決沙盒問題:

<application
    ...
    android:requestLegacyExternalStorage="true">
複製代碼

這樣咱們就能在「根目錄」建立本身文件了。

3. 適配 Android 11

Android 11 會強制執行沙盒模式,在這以前存儲權限能夠簡單的分爲「禁止」和「容許」,在這以後存儲權限能夠簡單的分爲「禁止」、「容許訪問媒體文件」和「容許訪問全部文件」。

「容許訪問媒體文件」這是絕大多數應用可以申請到的,而「容許訪問全部文件」只有文件管理類應用能夠申請到。假如你不是該類應用但又申請了該權限,那麼就會通不過Google Play的審覈。

容許訪問全部文件:android.permission.MANAGE_EXTERNAL_STORAGE

介紹到這兒,其實一個方案已經出來了:直接申請「容許訪問全部文件」權限,後果就是不能經過Google Play的審覈。

另外還有一個辦法:咱們暫時不升級SDK,針對 Android 10 (SDK 29)來開發應用,這樣的話因爲「向後兼容機制」,咱們的應用是可以正常跑在 Android 11 系統上的。

4. Flutter 代碼實踐

import 'dart:io';
import 'package:uuid/uuid.dart';

// 本地持久化存儲uuid代碼實踐
class Storage {
  static File file;

  // 入口
  static Future<String> init() async {
    bool boolCreateFile = await createFile();
    if (boolCreateFile) {
      String uuid = await readData();
      return uuid;
    } else {
      await writeData();
      String uuid = await readData();
      return uuid;
    }
  }

  // 建立文件
  static Future<bool> createFile() async {
    file = File('/storage/emulated/0/uuid.ini'); // 指向根目錄下的文件uuid
    bool exists = await file.exists();
    return exists;
  }

  // 寫入數據
  static writeData() async {
    // 若是文件存在,會將原來的內容覆蓋, 若是不存在,則建立文件
    String uuid = await getUuid();
    file.writeAsString('$uuid');
  }

  // 讀取文件
  static Future<String> readData() async {
    try {
      String uuid = await file.readAsString();
      return uuid;
    } catch (e) {
      return null;
    }
  }

  // 獲取uuid,採用的插件:uuid
  static Future<String> getUuid() async {
    Uuid uuidObj = Uuid();
    String uuid = uuidObj.v1();
    return uuid;
  }
}
複製代碼

三. 最後

不要吝嗇各位手裏的贊啊!

End.

相關文章
相關標籤/搜索