穩定獲取Android設備唯一碼(UUID)的解決方案


最近做的一個項目中需要用到Android設備唯一碼(UUID)來標識一台設備,

Android中設備唯一碼有很多,如:MAC地址、IMEI號(DeviceId)、IMSI號、ANDROID_ID、序列號(SerialNumber)等,

但並不是所有設備上都能穩定獲取到這些值。

 

最后項目中采用的是MAC地址。

先總結一些搜索得知的各種值的缺點,再說說最后采用MAC地址的解決方案吧。

 

1.MAC地址:

獲取MAC地址的方法有兩種:

(1). 通過Linux命令查詢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  String getMacAddress() {
      String macAddress = null ;
      String str = "" ;
      try {
         //linux下查詢網卡mac地址的命令
          Process pp = Runtime.getRuntime().exec( "cat /sys/class/net/wlan0/address" );
          InputStreamReader ir = new InputStreamReader(pp.getInputStream());
          LineNumberReader input = new LineNumberReader(ir);
 
          for (; null != str;) {
              str = input.readLine();
              if (str != null ) {
                  macAddress = str.trim();// 去空格
                  break ;
              }
          }
      } catch (IOException ex) {
          ex.printStackTrace();
      }
      return macAddress;
}

缺點:

在當前沒打開WiFi的情況下獲取得到的MAC地址值為空,即使在執行這段代碼前是有打開過WiFi,而執行這段代碼時WiFi狀態是關閉的,也不能獲取到MAC地址。

 

(2). 通過Android官方的WifiManager類獲取

1
2
3
4
5
6
7
8
9
10
11
public  String getMacAddress() {
 
      String macAddress = null ;
         
      WifiManager wifiManager =
          (WifiManager)MyApplication.getContext().getSystemService(Context.WIFI_SERVICE);
      WifiInfo info = ( null == wifiManager ? null : wifiManager.getConnectionInfo());
         
      macAddress = info.getMacAddress();
      return macAddress;
}

需要加入權限

1
<  uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />

缺點:

這種方法雖然能在當前Wifi狀態為關閉的情況下獲取到MAC地址,但前提是在手機開機后要打開過一次Wifi,如果在某次開機后沒打開過Wifi就調用這段代碼,獲取地址也是為空。

網上給出的解釋是:WiFi的Mac address是一個被動資訊。一般在開機后,不會主動上報到系統裡。要待WiFi硬件啟動后,才會把有關Mac address資料記載入系統去。

 

2.IMEI號(DeviceId)、IMSI號:

1
2
3
TelephonyManager mTelephonyMgr = (TelephonyManager) getSystemServic(Context.TELEPHONY_SERVICE);
String imsi = mTelephonyMgr.getSubscriberId();  //獲取IMSI號
String imei = mTelephonyMgr.getDeviceId();  //獲取IMEI號

需要加入權限

1
<  uses-permission android:name = "android.permission.READ_PHONE_STATE" />

缺點:

IMEI號(國際移動設備身份碼)、IMSI號(國際移動設備識別碼)這兩個是有電話功能的移動設備才具有,也就是說某些沒有電話功能的平板是獲取不到IMEI和IMSI號的。且在某些設備上getDeviceId()會返回垃圾數據。

 

3.ANDROID_ID:

ANDROID_ID 是設備首次啟動時由系統隨機生成的一串64位的十六進制數字。

1
String ANDROID_ID = Settings.System.getString(getContentResolver(), Settings.System.ANDROID_ID);

缺點:

①.設備刷機wipe數據或恢復出廠設置時ANDROID_ID值會被重置。

②.現在網上已有修改設備ANDROID_ID值的APP應用。

③.某些廠商定制的系統可能會導致不同的設備產生相同的ANDROID_ID。

④.某些廠商定制的系統可能導致設備返回ANDROID_ID值為空。

⑤.CDMA設備,ANDROID_ID和DeviceId返回的值相同

 

4.序列號SerialNumber:

從Android 2.3開始,通過android.os.Build.SERIAL方法可獲取到一個序列號。沒有電話功能的設備也都需要上給出此唯一的序列號。

1
String SerialNumber = android.os.Build.SERIAL;

缺點:

在某些設備上此方法會返回垃圾數據。

 

解決方案:

一種比較折衷的辦法,在獲取MAC地址之前先判斷當前WiFi狀態,若開啟了Wifi,則直接獲取MAC地址,若沒開啟Wifi,則用代碼開啟Wifi,然后馬上關閉,再獲取MAC地址。

目前此方法測試成功,無論在哪種狀態下都能正確取得設備的MAC地址(包括開機后未啟動過Wifi的狀態下),且在未開啟Wifi的狀態下,用代碼開啟Wifi並馬上關閉,過程極短,不會影響到用戶操作。

代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public  String getMacAddress() {
 
      String macAddress = null ;
      WifiManager wifiManager =
          (WifiManager)MyApplication.getContext().getSystemService(Context.WIFI_SERVICE);
      WifiInfo info = ( null == wifiManager ? null : wifiManager.getConnectionInfo());
         
      if (!wifiManager.isWifiEnabled())
      {
         //必須先打開,才能獲取到MAC地址
          wifiManager.setWifiEnabled( true );
          wifiManager.setWifiEnabled( false );
      }
      if ( null != info) {
          macAddress = info.getMacAddress();
      }
      return macAddress;
}

需要加入如下權限

1
2
3
<  uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" > </ uses-permission >
<  uses-permission android:name = "android.permission.CHANGE_WIFI_STATE" > </ uses-permission >
<  uses-permission android:name = "android.permission.WAKE_LOCK" > </ uses-permission >

 

來自:http://www.goteny.com/develop/android/201412/452.html

 

極光推送的設備唯一性標識 RegistrationID

對於 App 雲平台系統,如何唯一地識別移動設備是非常重要的。否則,每次用戶在設備上卸載掉應用再重新安裝,后端系統只能把這個用戶當作一個全新的用戶了。

Android 上識別設備的唯一性,因為這個圈太亂,所以設備本身的任何標識都是無法直接用作設備唯一標識的。iOS 是系統強力限制被唯一識別的,目前唯一可以部分滿足條件是 IDFA,但需要你的 App 本身的確嵌入了廣告。

很多開發者使用極光推送時,都有這個疑問:極光推送是如何來做設備的唯一性識別的。本文解析極光推送如何盡可能地來唯一識別設備。

極光推送對安裝在設備上的 App 使用 RegistrationID 作為標識。極光推送要『盡可能』確保設備的唯一性,就是要使得 RegistrationID 盡可能唯一。

RegistrationID 的定義

關於 RegistrationID 極光官方文檔有如下的定義:

集成了 JPush SDK 的應用程序在第一次 App 啟動后,成功注冊到 JPush 服務器時,JPush 服務器會給客戶端返回唯一的該設備的標識 – RegistrationID。JPush SDK 會以廣播的形式發送 RegistrationID 到應用程序。

有了這個標識,App 編程可以把這個 RegistrationID 保存到自己的應用服務器上,然后就可以根據 RegistrationID 來向設備推送消息或者通知。

RegistrationID 變化可能性

如果 App 不卸載,是直接覆蓋安裝,Android, iOS 上 RegistrationID 的值都不會變化。

如果 App 是卸載之后再次安裝:

  • Android 上 RegistrationID 基本不會變;
  • iOS 上如果啟用了 IDFA 變化可能性不大,如果未啟用 IDFA 則每次安裝 RegistrationID 都會變;

RegistrationID 生成規則解析

Android 平台

Android 上因為國內存在大量山寨設備的原因,正常的 IMEI, Mac Address, AndroidID 這些可以考慮用作唯一標識的值,都是不可以用的,因為這些值在一批設備中可能都是同一個值。

極光的基本思路是:

  1. 生成一個 DeviceID 保存到 Settings, External Storage。依賴本地存儲,應用被卸載后重新安裝這些存儲里的 DeviceID 還在的話,就是同一個設備。這一條理論上解決 90% 的不變性問題。
  2. DeviceID 之外增加補充規則:綜合根據 IMEI, MAC Address, AndroidID 這幾個值來判斷,是否可能是老設備。

具體的邏輯細節,也是根據實際運行情況,以及收集到的反饋不斷調整的,大多數邏輯可在服務器端調整。

iOS平台

鑒於 iOS 系統設計上限制設備唯一標識,所以極光一直使用 Device Token 作為標識,也因為極光推送本身就是需要 Device Token 這個值才可能運作的。

iOS 9 版本之后,每次卸載后重裝都會導致 Device Token 變化,所以對於極光后台來說,都只能被識別為新用戶。

極光 SDK 新版本增加了 IDFA 選項,在集成初始化 SDK 時可選把 IDFA 這個值設置進來,這樣極光后台就優先根據 IDFA 值來識別用戶,從有一定的可能性應用被卸載后重裝還能識別回老設備。

IDFA 是廣告標識符,是 iOS 專門為廣告跟蹤唯一地識別用戶而設計的。在 iOS 設備上,設備 -> 隱私 -> 廣告這個頁面,有一個設置項:限制廣告跟蹤。默認是未選中狀態的,即是關閉狀態,是不限制的。用戶可以選中,從而限制廣告跟蹤。設置項之外還有一個按鈕:還原廣告標識符…。如果用戶點擊了這個按鈕,則 IDFA 值會變化。

2115454-b0c648ae038d8d0a

 

 

默認的情況下,沒有限制廣告跟蹤,可以取到 IDFA 這個值。並且用戶未點擊『還原廣告標識』時,這個值是不會變的。這樣就達到了唯一地標識設備、跟蹤到用戶的目標。

但是,但是,請一定留意,IDFA 並不是一定可以啟用的,是需要你的 App 的確有廣告功能才可以用的,否則 Apple 在上架審核時有可能發現從而拒絕上架。

關於蘋果 App 上架對 IDFA 的要求,可參考這里的說明:The Advertising Identifier (IDFA)

高級使用建議

因為 RegistrationID 是 JPush SDK 注冊完成之后才得到的,所以調用 SDK API 來獲取 RegistrationID 的值時需要稍注意,不是總能夠立即得到。

比如 iOS 上建議在監聽到 kJPFNetworkDidLoginNotification 這個通知后的代碼里,來獲取 RegistrationID 的值。

Android 上有寫 Settings 的權限,是可以寫數據到 Settings 里邊的,相當於被當作一個永久存儲點了。 外部存儲一般指 SDCard,現在越來越多手機直接手機自帶了,類似於 iPhone 的作法。

這 2 個點如果數據都被破壞了,就的確通過本地 DeviceID 存儲無法確認為唯一設備了。但是,服務器端還可以通過 IMEI/AndroidID 這些靈活地確認到是否同一設備。

 以上轉自  http://blog.jiguang.cn/registrationid/

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM