|
|
@@ -0,0 +1,408 @@
|
|
|
+package com.sheep.gamegroup.util;
|
|
|
+
|
|
|
+import android.Manifest;
|
|
|
+import android.content.Context;
|
|
|
+import android.content.SharedPreferences;
|
|
|
+import android.content.pm.PackageManager;
|
|
|
+import android.net.wifi.WifiManager;
|
|
|
+import android.os.Build;
|
|
|
+import android.os.Environment;
|
|
|
+import android.support.v4.app.ActivityCompat;
|
|
|
+import android.telephony.TelephonyManager;
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.Base64;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import com.sheep.gamegroup.model.api.BaseMessageConverter;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.io.FileNotFoundException;
|
|
|
+import java.io.FileOutputStream;
|
|
|
+import java.io.FileReader;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStreamReader;
|
|
|
+import java.io.LineNumberReader;
|
|
|
+import java.io.Reader;
|
|
|
+import java.net.NetworkInterface;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.List;
|
|
|
+import java.util.UUID;
|
|
|
+
|
|
|
+import javax.crypto.Cipher;
|
|
|
+import javax.crypto.spec.IvParameterSpec;
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Created by realicing on 2018/5/24.
|
|
|
+ * realicing@sina.com
|
|
|
+ */
|
|
|
+public class DeviceIDUtil {
|
|
|
+
|
|
|
+ /*
|
|
|
+ *
|
|
|
+ * <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
|
|
+ * <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
|
+ * <uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
|
|
+ *
|
|
|
+ * */
|
|
|
+ private static final String SHARED_PREFERENCES_NAME = "deviceid_cache";
|
|
|
+ //.开头隐藏文件和隐藏文件夹
|
|
|
+ private static final String FILE_PATH = "data/.cache/.1270f37f6c8";
|
|
|
+
|
|
|
+ private static final String LOACL_UUID = "my_device_localuuid";
|
|
|
+ private static final String LOACL_MAC = "my_device_local_mac";
|
|
|
+ private static final String LOACL_IMEI = "my_device_local_imei";
|
|
|
+ private static final String LOACL_DEVICE_IMEI = "my_device_local_device_imei";
|
|
|
+
|
|
|
+
|
|
|
+ private static final String LOACL_DEVICE_ID = "my_device_loacl_device_id";
|
|
|
+
|
|
|
+ private static final String LOACL_FILENAME_KEY = "loacl_filename_key";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //获取设备唯一id
|
|
|
+ public static String getDeviceId(Context mContext) {
|
|
|
+ /* Log.d("DeviceIDUtils", "getLocalDeviceId:" + getLocalDeviceId());
|
|
|
+ Log.d("DeviceIDUtils", "getMacid:" + getMacid());
|
|
|
+ Log.d("DeviceIDUtils", "getMac60:" + getMac60());
|
|
|
+ Log.d("DeviceIDUtils", "getMac60_1:" + getMac60_1());
|
|
|
+ Log.d("DeviceIDUtils", "getMac60_2:" + getMac60_2());
|
|
|
+ Log.d("DeviceIDUtils", "getimei:" + getimei());
|
|
|
+ Log.d("DeviceIDUtils", "getDiviceInfoIMEI:" + getDiviceInfoIMEI());
|
|
|
+ Log.d("DeviceIDUtils", "getLocalUUID:" + getLocalUUID());
|
|
|
+ Log.d("DeviceIDUtils", "getFileName:" + getFileName());
|
|
|
+*/
|
|
|
+ String localDeviceId = getLocalDeviceId(mContext);
|
|
|
+ if (!TextUtils.isEmpty(localDeviceId)) {
|
|
|
+ return localDeviceId;
|
|
|
+ }
|
|
|
+ //先获取获取默认的imei
|
|
|
+ String diviceid = getimei(mContext);
|
|
|
+
|
|
|
+ //如果为空获取MAC地址
|
|
|
+ if (TextUtils.isEmpty(diviceid)) {
|
|
|
+ diviceid = getMacid(mContext);
|
|
|
+ }
|
|
|
+
|
|
|
+ //如果还为空择取设备信息拼接出来的id
|
|
|
+ if (TextUtils.isEmpty(diviceid)) {
|
|
|
+ diviceid = getDiviceInfoIMEI(mContext);
|
|
|
+ }
|
|
|
+
|
|
|
+ //如果还为空则生成并保存一个唯一的UUID
|
|
|
+ if (TextUtils.isEmpty(diviceid)) {
|
|
|
+ diviceid = getLocalUUID(mContext);
|
|
|
+ }
|
|
|
+
|
|
|
+ Log.d("DeviceIDUtils", "return diviceid:" + diviceid);
|
|
|
+ saveDeviceId(mContext, diviceid);
|
|
|
+ return diviceid;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String getLocalDeviceId(Context mContext) {
|
|
|
+ String savaString = getSavaString(mContext, LOACL_DEVICE_ID, "");
|
|
|
+ if (TextUtils.isEmpty(savaString)) {
|
|
|
+ String s = readSDFile();
|
|
|
+ if (!TextUtils.isEmpty(s)) {
|
|
|
+ savaString(mContext, LOACL_DEVICE_ID, s);
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return savaString;
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void saveDeviceId(Context mContext, String diviceid) {
|
|
|
+ savaString(mContext, LOACL_DEVICE_ID, diviceid);
|
|
|
+ //加密保存
|
|
|
+ saveFile(BaseMessageConverter.encrypt(diviceid));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void saveFile(String str) {
|
|
|
+ String filePath = null;
|
|
|
+ boolean hasSDCard = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
|
|
|
+ if (hasSDCard) { // SD卡根目录的hello.text
|
|
|
+ filePath = Environment.getExternalStorageDirectory().toString() + File.separator + FILE_PATH + File.separator + getFileName();
|
|
|
+ } else { // 系统下载缓存根目录的hello.text
|
|
|
+ filePath = Environment.getDownloadCacheDirectory().toString() + File.separator + FILE_PATH + File.separator + getFileName();
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ File file = new File(filePath);
|
|
|
+ //不存在則重新保存
|
|
|
+ if (!file.exists()) {
|
|
|
+ Log.d("DeviceIDUtils", "saveFile filePath:" + filePath);
|
|
|
+ File dir = new File(file.getParent());
|
|
|
+ dir.mkdirs();
|
|
|
+ file.createNewFile();
|
|
|
+ FileOutputStream outStream = new FileOutputStream(file);
|
|
|
+ outStream.write(str.getBytes());
|
|
|
+ outStream.close();
|
|
|
+ } else {
|
|
|
+ Log.d("DeviceIDUtils", "saveFile 文件已存在:" + filePath);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String getFileName() {
|
|
|
+ //两种模式,随机的文件名和固定文件名,可以根据需求自行更换
|
|
|
+ //随机的文件名
|
|
|
+ /* String savaFileName = getSavaString(LOACL_FILENAME_KEY, "");
|
|
|
+ if (TextUtils.isEmpty(savaFileName)) {
|
|
|
+ String uuid = UUID.randomUUID().toString().replace("-", "");
|
|
|
+ savaString(LOACL_FILENAME_KEY, uuid);
|
|
|
+ Log.d("DeviceIDUtils", "getFileName:" + uuid);
|
|
|
+ return uuid;
|
|
|
+ } else {
|
|
|
+ Log.d("DeviceIDUtils", "getFileName:" + savaFileName);
|
|
|
+ return savaFileName;
|
|
|
+ }*/
|
|
|
+
|
|
|
+
|
|
|
+ //固定文件名
|
|
|
+ return ".abcdefg60232414f87c77dcc737f2f0c";
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String readSDFile() {
|
|
|
+ try {
|
|
|
+ String filePath = null;
|
|
|
+ boolean hasSDCard = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
|
|
|
+ if (hasSDCard) { // SD卡根目录的hello.text
|
|
|
+ filePath = Environment.getExternalStorageDirectory().toString() + File.separator + FILE_PATH + File.separator + getFileName();
|
|
|
+ } else { // 系统下载缓存根目录的hello.text
|
|
|
+ filePath = Environment.getDownloadCacheDirectory().toString() + File.separator + FILE_PATH + File.separator + getFileName();
|
|
|
+ }
|
|
|
+ File file = new File(filePath);
|
|
|
+ FileInputStream fis = new FileInputStream(file);
|
|
|
+ int length = fis.available();
|
|
|
+
|
|
|
+ byte[] buffer = new byte[length];
|
|
|
+ fis.read(buffer);
|
|
|
+ String res = new String(buffer, "utf-8");
|
|
|
+ fis.close();
|
|
|
+ Log.d("DeviceIDUtils", "readSDFile filePath:" + filePath);
|
|
|
+ Log.d("DeviceIDUtils", "readSDFile res:" + res);
|
|
|
+ //解密
|
|
|
+ return BaseMessageConverter.decrypt(res);
|
|
|
+ } catch (FileNotFoundException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static String getLocalUUID(Context mContext) {
|
|
|
+ String localuuid = getSavaString(mContext, LOACL_UUID, "");
|
|
|
+ if (TextUtils.isEmpty(localuuid)) {
|
|
|
+ localuuid = UUID.randomUUID().toString().replace("-", "");
|
|
|
+ savaString(mContext, LOACL_UUID, localuuid);
|
|
|
+ }
|
|
|
+ return localuuid;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String getMacid(Context mContext) {
|
|
|
+ String WLANMAC = getSavaString(mContext, LOACL_MAC, "");
|
|
|
+ if (!TextUtils.isEmpty(WLANMAC)) {
|
|
|
+ return WLANMAC;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Build.VERSION.SDK_INT >= 23) {
|
|
|
+ WLANMAC = getMac60();
|
|
|
+ } else {
|
|
|
+ WifiManager wm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
|
|
+ WLANMAC = wm.getConnectionInfo().getMacAddress();
|
|
|
+ if (TextUtils.isEmpty(WLANMAC) || "02:00:00:00:00:00".equals(WLANMAC)) {
|
|
|
+ WLANMAC = getMac60();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //在Android6.0的版本以后用原来的getMacAddress()方法获取手机的MAC地址都为:02:00:00:00:00:00这个固定的值
|
|
|
+ if ("02:00:00:00:00:00".equals(WLANMAC)) {
|
|
|
+ WLANMAC = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!TextUtils.isEmpty(WLANMAC)) {
|
|
|
+ WLANMAC = WLANMAC.replaceAll(":", "");
|
|
|
+ savaString(mContext, LOACL_MAC, WLANMAC);
|
|
|
+ }
|
|
|
+ return WLANMAC;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static String getMac60() {
|
|
|
+ String mac = getMac60_1();
|
|
|
+ if (TextUtils.isEmpty(mac) || "02:00:00:00:00:00".equals(mac)) {
|
|
|
+ mac = getMac60_2();
|
|
|
+ }
|
|
|
+ return mac;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String getMac60_1() {
|
|
|
+ String str = "";
|
|
|
+ String macSerial = "";
|
|
|
+ try {
|
|
|
+ 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) {
|
|
|
+ macSerial = str.trim();// 去空格
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ ex.printStackTrace();
|
|
|
+ }
|
|
|
+ if (TextUtils.isEmpty(macSerial)) {
|
|
|
+ try {
|
|
|
+ return loadFileAsString("/sys/class/net/eth0/address")
|
|
|
+ .toUpperCase().substring(0, 17);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //转换成小写
|
|
|
+ if (!TextUtils.isEmpty(macSerial)) {
|
|
|
+ macSerial = macSerial.toLowerCase();
|
|
|
+ }
|
|
|
+ return macSerial;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String getMac60_2() {
|
|
|
+ try {
|
|
|
+ List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
|
|
|
+ for (NetworkInterface nif : all) {
|
|
|
+ if (!nif.getName().equalsIgnoreCase("wlan0")) continue;
|
|
|
+
|
|
|
+ byte[] macBytes = nif.getHardwareAddress();
|
|
|
+ if (macBytes == null) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ StringBuilder res1 = new StringBuilder();
|
|
|
+ for (byte b : macBytes) {
|
|
|
+ res1.append(String.format("%02X:", b));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (res1.length() > 0) {
|
|
|
+ res1.deleteCharAt(res1.length() - 1);
|
|
|
+ }
|
|
|
+ String mac = res1.toString();
|
|
|
+ //转换成小写
|
|
|
+ if (!TextUtils.isEmpty(mac)) {
|
|
|
+ mac = mac.toLowerCase();
|
|
|
+ }
|
|
|
+ return mac;
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String loadFileAsString(String fileName) throws Exception {
|
|
|
+ FileReader reader = new FileReader(fileName);
|
|
|
+ String text = loadReaderAsString(reader);
|
|
|
+ reader.close();
|
|
|
+ return text;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String loadReaderAsString(Reader reader) throws Exception {
|
|
|
+ StringBuilder builder = new StringBuilder();
|
|
|
+ char[] buffer = new char[4096];
|
|
|
+ int readLength = reader.read(buffer);
|
|
|
+ while (readLength >= 0) {
|
|
|
+ builder.append(buffer, 0, readLength);
|
|
|
+ readLength = reader.read(buffer);
|
|
|
+ }
|
|
|
+ return builder.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //通过取出ROM版本、制造商、CPU型号、以及其他硬件信息来实现
|
|
|
+ private static String getDiviceInfoIMEI(Context mContext) {
|
|
|
+ String device_imei = getSavaString(mContext, LOACL_DEVICE_IMEI, "");
|
|
|
+ if (!TextUtils.isEmpty(device_imei)) {
|
|
|
+ return device_imei;
|
|
|
+ }
|
|
|
+
|
|
|
+ device_imei = "35" + //we make this look like a valid IMEI
|
|
|
+ Build.BOARD.length() % 10 +
|
|
|
+ Build.BRAND.length() % 10 +
|
|
|
+ Build.CPU_ABI.length() % 10 +
|
|
|
+ Build.DEVICE.length() % 10 +
|
|
|
+ Build.DISPLAY.length() % 10 +
|
|
|
+ Build.HOST.length() % 10 +
|
|
|
+ Build.ID.length() % 10 +
|
|
|
+ Build.MANUFACTURER.length() % 10 +
|
|
|
+ Build.MODEL.length() % 10 +
|
|
|
+ Build.PRODUCT.length() % 10 +
|
|
|
+ Build.TAGS.length() % 10 +
|
|
|
+ Build.TYPE.length() % 10 +
|
|
|
+ Build.USER.length() % 10; //13 digits
|
|
|
+
|
|
|
+ if (!TextUtils.isEmpty(device_imei)) {
|
|
|
+ savaString(mContext, LOACL_DEVICE_IMEI, device_imei);
|
|
|
+ }
|
|
|
+ return device_imei;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String getimei(Context mContext) {
|
|
|
+ String imei = getSavaString(mContext, LOACL_IMEI, "");
|
|
|
+ if (!TextUtils.isEmpty(imei)) {
|
|
|
+ return imei;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ TelephonyManager tm = (TelephonyManager) mContext
|
|
|
+ .getSystemService(Context.TELEPHONY_SERVICE);
|
|
|
+ if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
|
|
|
+ // TODO: Consider calling
|
|
|
+ // ActivityCompat#requestPermissions
|
|
|
+ // here to request the missing permissions, and then overriding
|
|
|
+ // public void onRequestPermissionsResult(int requestCode, String[] permissions,
|
|
|
+ // int[] grantResults)
|
|
|
+ // to handle the case where the user grants the permission. See the documentation
|
|
|
+ // for ActivityCompat#requestPermissions for more details.
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if(tm == null)
|
|
|
+ return null;
|
|
|
+ imei = tm.getDeviceId();
|
|
|
+ if (!TextUtils.isEmpty(imei)) {
|
|
|
+ savaString(mContext, LOACL_IMEI, imei);
|
|
|
+ }
|
|
|
+ return imei;
|
|
|
+ } catch (Exception e) {
|
|
|
+
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String getSavaString(Context mContext, String key, String defValue) {
|
|
|
+ SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
|
|
+ return sp.getString(key, defValue);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void savaString(Context mContext, String key, String value) {
|
|
|
+ SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
|
|
+ sp.edit().putString(key, value).apply();//提交保存键值对
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|