sonic-agent是如何监控Android设备上下线的

392 阅读2分钟

核心目标

  1. 什么是ddmlib?
  2. 如何实现Android设备连接监听?
  3. 如何实现Android设备管理?

解答1:

ddmlib是Google提供的基于Java的adb封装库,包含了很多实用的设备操作方法。

解答2:

主要有以下几个步骤

  1. 实现AndroiDebugBridge的IDeviceChangeListener接口,并定义设备连接和断开时的操作内容
  2. 设置监听器,并初始化AndroidDebugBridge
  3. 测试监听效果
/**
 * 实现IDeviceChangeListener接口,其中包含deviceConnected和deviceDisconnected
 * deviceChanged方法在实践中测试可以不用写业务逻辑。
**/
@Component
@Slf4j
public class AndroidDeviceStatusListener implements AndroidDebugBridge.IDeviceChangeListener {
    @Override
    public void deviceConnected(IDevice device) {
        log.info("Device: " + device.getSerialNumber() + " is online......");
    }

    @Override
    public void deviceDisconnected(IDevice device) {
        log.info("Device: " + device.getSerialNumber() + " is offline......");
    }

    @Override
    public void deviceChanged(IDevice device, int changeMask) {
//        log.info("Device: " + device.getSerialNumber() + " state changed: " + device.getState().toString());
    }
}
/**
 * 结合Springboot特性,实现了ApplicationListener的接口,会在Bean初始化时调用onApplicationEvent
 * 的方法,实现自动配置
 * 注意,不要一上来就直接调用getDevices()的方法,那样大概率会拿到一个空的设备列表,推荐的做法是自己
 * 在监听器里面设备上线时自身维护一个deviceMap,或者循环等待下hasInitialDeviceList这个方法
**/
@Component
@Slf4j
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class AndroidDeviceBridgeTool implements ApplicationListener<ContextRefreshedEvent> {

    @Resource
    private AndroidDeviceStatusListener androidDeviceStatusListener;

    private ConfigurableApplicationContext context;

    public static AndroidDebugBridge androidDebugBridge = null;

    @Autowired
    public void setContext(ConfigurableApplicationContext context){
        this.context = context;
    }
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        String adbPath = getADBPath();
        if (!StringUtils.hasLength(adbPath)){
            log.info("no adb env found......");
            context.close();
            System.exit(0);
        }
        AndroidDebugBridge.addDeviceChangeListener(androidDeviceStatusListener);
        try{
            AndroidDebugBridge.init(false);
            androidDebugBridge = AndroidDebugBridge.createBridge(adbPath, true, Long.MAX_VALUE, TimeUnit.MICROSECONDS);
            if (androidDebugBridge != null){
                log.info("Android device is listening........");
            }
        }catch (Exception e){
            log.error("ADB Service 启动异常");
            context.close();
            System.exit(0);
        }
        if (androidDebugBridge != null){
            int count = 0;
            while (!androidDebugBridge.hasInitialDeviceList()){
                try{
                    Thread.sleep(500);
                }catch (Exception e){
                    log.error("Thread sleep exception: " + e.getMessage());
                }
                if (count > 100){
                    break;
                }
                ++count;
            }
            log.info("count is " + count);
            if (count > 100){
                // 说明未初始化设备列表,可能是因为故障原因
                log.info("adb initialize failed, exit......");
                context.close();
                System.exit(0);
            }
        }
    }


    private static String getADBPath(){
        String path = System.getenv("ANDROID_HOME");
        if (StringUtils.hasLength(path)){
            path += File.separator + "platform-tools" + File.separator + "adb";
            if (System.getProperty("os.name").toLowerCase().contains("win")){
                path += ".exe";
            }
            return path;
        }
        return null;
    }
}

这里要注意一个细节,就是上面这个while中对于hasInitialDeviceList的判断,因为adb初始化需要一定的时间。如果在androidDebugBridge初始化完成后,就立马调用deviceList获取设备列表的方法,那有可能会返回empty list,因此需要进行等待,如果等待超出了设定的范围还是没有获取到列表信息,那就直接退出系统。

解答3

当设备上下线可以被捕获后,设备管理就变得很简单了,无论是数据库同步还是页面展示,只需要取出对应支持的设备serialNumber即可。