Android10以上实现获取设备唯一标识,目前只支持华为和荣耀设备。实现原理:通过无障碍服务读取序列号界面。
public class DeviceHelper implements Application.ActivityLifecycleCallbacks {
static final String TAG = "WADQ_DeviceHelper";
static final String ACTION_ACQUIRE_SERIAL_SUCCESS = "zwxuf.intent.action.ACQUIRE_SERIAL_SUCCESS";
private static Handler mHandler = new Handler(Looper.getMainLooper());
private boolean isMsgReceiverEnabled;
private OnAcquireSerialListener mOnAcquireSerialListener;
private Activity mActivity;
private Application mApplication;
public DeviceHelper(Activity mActivity) {
this.mActivity = mActivity;
mApplication = mActivity.getApplication();
mApplication.registerActivityLifecycleCallbacks(this);
}
public void acquireSerial(OnAcquireSerialListener listener) {
mOnAcquireSerialListener = listener;
if (!isMsgReceiverEnabled) initMsgReceiver();
AcquireSerialService.isSerialFound = false;
AcquireSerialService.isStatusInfoFound = false;
Intent intent = new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mActivity.startActivity(intent);
}
private void releaseAcquireSerial() {
List<Service> services = getServices();
for (Service service : services) {
if (service instanceof AcquireSerialService) {
((AcquireSerialService) service).release();
break;
}
}
}
private void initMsgReceiver() {
IntentFilter filter = new IntentFilter(ACTION_ACQUIRE_SERIAL_SUCCESS);
mActivity.registerReceiver(mMsgReceiver, filter);
isMsgReceiverEnabled = true;
}
private BroadcastReceiver mMsgReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String serial = intent.getStringExtra("serial");
if (mOnAcquireSerialListener != null) {
mOnAcquireSerialListener.onAcquireSerial(serial);
}
releaseMsgReciever();
}
};
private void releaseMsgReciever() {
if (isMsgReceiverEnabled) {
mActivity.unregisterReceiver(mMsgReceiver);
isMsgReceiverEnabled = false;
}
}
public void release() {
releaseMsgReciever();
mApplication.unregisterActivityLifecycleCallbacks(this);
releaseAcquireSerial();
}
public boolean canAcquireSerial() {
return isServiceEnabled(mActivity, AcquireSerialService.class);
}
public void openAcquireSerialSettings(final int requestCode) {
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
mActivity.startActivityForResult(intent, requestCode);
} catch (Exception e) {
e.printStackTrace();
}
}
private static boolean isServiceEnabled(Context context, Class<? extends AccessibilityService> serviceClass) {
if (serviceClass == null) {
return false;
}
String serviceName = context.getPackageName() + "/" + serviceClass.getName();
try {
int enabled = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED);
if (enabled == 1) {
String service = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
Log.i(TAG, service);
return service != null && service.contains(serviceName);
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
static Handler getHandler() {
return mHandler;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if (activity == mActivity) {
release();
}
}
private static List<Service> getServices() {
List<Service> services = new ArrayList<>();
Object mActivityThread = getActivityThread();
try {
Class mActivityThreadClass = mActivityThread.getClass();
Field mServicesField = mActivityThreadClass.getDeclaredField("mServices");
mServicesField.setAccessible(true);
Object mServices = mServicesField.get(mActivityThread);
if (mServices instanceof Map) {
Map<IBinder, Service> arrayMap = (Map) mServices;
for (Map.Entry<IBinder, Service> entry : arrayMap.entrySet()) {
Service service = entry.getValue();
if (service != null) {
services.add(service);
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return services;
}
private static Object getActivityThread() {
try {
Class ActivityThread = Class.forName("android.app.ActivityThread");
Method currentActivityThread = ActivityThread.getMethod("currentActivityThread");
currentActivityThread.setAccessible(true);
return currentActivityThread.invoke(null);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
}
public class AcquireSerialService extends AccessibilityService {
static boolean isStatusInfoFound;
static boolean isSerialFound;
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getPackageName() == null || event.getClassName() == null) {
return;
}
String packageName = event.getPackageName().toString();
String className = event.getClassName().toString();
final AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo != null) {
if (!packageName.equals(getApplicationContext().getPackageName())) {
enumChildNodeInfo(packageName, nodeInfo, 0);
}
}
}
@Override
public void onInterrupt() {
}
private Runnable mScrollRunnalbe;
private void enumChildNodeInfo(String packageName, AccessibilityNodeInfo nodeInfo, int level) {
int count = nodeInfo.getChildCount();
if (count > 0) {
for (int i = 0; i < count; i++) {
final AccessibilityNodeInfo childNodeInfo = nodeInfo.getChild(i);
if (childNodeInfo == null) continue;
if (childNodeInfo.isScrollable()) {
childNodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
if (!isSerialFound) {
String serial = getSerialByNodeInfo(packageName, childNodeInfo);
if (serial != null && !serial.isEmpty()) {
//获取到sn
Log.i(DeviceHelper.TAG, serial);
Intent intent = new Intent(DeviceHelper.ACTION_ACQUIRE_SERIAL_SUCCESS);
intent.putExtra("serial", serial);
sendBroadcast(intent);
performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
DeviceHelper.getHandler().postDelayed(new Runnable() {
@Override
public void run() {
performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
release();
}
}, 200);
return;
}
enumChildNodeInfo(packageName, childNodeInfo, level + 1);
}
}
}
nodeInfo.recycle();
}
private String getSerialByNodeInfo(String packageName, AccessibilityNodeInfo nodeInfo) {
if (nodeInfo.getText() == null) {
return null;
}
String text = nodeInfo.getText().toString();
if (text.equals("序列号")) {
isStatusInfoFound = true;
isSerialFound = true;
if (mScrollRunnalbe != null) {
DeviceHelper.getHandler().removeCallbacks(mScrollRunnalbe);
mScrollRunnalbe = null;
}
return getValue(nodeInfo);
} else if (packageName.equals("com.android.settings") && (text.equals("状态信息") || text.equals("状态消息")) && !isStatusInfoFound) {
isStatusInfoFound = true;
AccessibilityNodeInfo statusInfoParent = nodeInfo.getParent();
while (statusInfoParent != null && !statusInfoParent.isClickable()) {
statusInfoParent = statusInfoParent.getParent();
}
if (statusInfoParent != null) {
final AccessibilityNodeInfo finalStatusInfoParent = statusInfoParent;
DeviceHelper.getHandler().postDelayed(new Runnable() {
@Override
public void run() {
finalStatusInfoParent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}, 200);
}
}
return null;
}
private String getValue(AccessibilityNodeInfo nodeInfo) {
AccessibilityNodeInfo snLayout = nodeInfo.getParent();
if (snLayout != null) {
while (true) {
List<AccessibilityNodeInfo> snSummaryList = snLayout.findAccessibilityNodeInfosByViewId("android:id/summary");
if (snSummaryList != null && !snSummaryList.isEmpty()) {
AccessibilityNodeInfo snSummary = snSummaryList.get(0);
if (snSummary != null && snSummary.getText() != null) {
return snSummary.getText().toString();
}
}
snLayout = snLayout.getParent();
if (snLayout == null) {
break;
}
}
}
return null;
}
private String getNodeText(AccessibilityNodeInfo nodeInfo) {
if (nodeInfo != null && nodeInfo.getText() != null) {
return nodeInfo.getText().toString();
} else {
return null;
}
}
public void release() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
disableSelf();
}
}
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private DeviceHelper mDeviceHelper;
private TextView tv_serial, tv_phone;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_serial = findViewById(R.id.tv_serial);
mDeviceHelper = new DeviceHelper(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bn_get_serial:
getSerial();
break;
}
}
private void getSerial() {
if (!mDeviceHelper.canAcquireSerial()) {
new AlertDialog.Builder(this)
.setMessage("没有开启无障碍服务")
.setPositiveButton("去开启", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mDeviceHelper.openAcquireSerialSettings(1000);
}
})
.setNegativeButton("取消", null)
.create()
.show();
return;
}
mDeviceHelper.acquireSerial(new OnAcquireSerialListener() {
@Override
public void onAcquireSerial(String serial) {
//Toast.makeText(MainActivity.this, serial, Toast.LENGTH_SHORT).show();
tv_serial.setText("sn:" + serial);
}
});
}
}