IOS Android 手机助手原理以及源码(Android 手机自动识别 一)

来源:互联网 发布:量子通信网络快吗 编辑:程序博客网 时间:2024/05/16 12:19

Android 的手机自动识别就比IOS 的要复杂的多了。其实iTunes 已经把所有的事情都做好了,但是android 就需要我们自己一步一步来了。过程大致如下

1) 监视USB 设备的插入和拔出

2) 判断USB 设备是否是一个android 手机

3) 如果是一个android 手机,需要判断是否已经安装好驱动,否则我们就得给手机装驱动了。

4) 和手机进行通信。如果是获取非常简单的信息,可以直接通过adb 来获取,但是想要获取比较复杂的东西,或者修改手机的内容,那就需要借助App 来实现了。


上面4个步骤中只有步骤2是难点。其他步骤都是基于代码实现,代码写好了功能自然就有了。但是步骤2却不一样。因为识别一个usb 设备是否是手机最重要的一步是VID,PID。当然VID,PID 是最重要一步,还有其他的一些识别方法。如果有一个庞大的VID,PID 数据库那就会非常简单,只要查一下这个USB 设备的VID,PID 是否在库里面就可以了,但是目前并没有一个地方可以获取到这个库,只能是靠一点一点的收集起来。所以对于Android的手机助手来说,步骤2是一个必须要迈过的砍。如果是mac 系统则稍微有点不同,步骤三的驱动安装是否需要目前我还没有搞清楚,再mac 上安装完eclipse 后几个android 手机就能发现设备了。

接下来一步一步来讲解

一  监视USB 设备的插入和拔出

     1) windows

        大家都知道windows GUI程序是基于消息循环的,当USB 设备插入和拔出的时候,windows 操作系统会给所有的窗口发送WM_DEVICECHANGE消息。所以我们的程序必须要有一个窗口。否则没法捕获消息。所以第一步就很简单,监听系统的WM_DEVICECHANGE消息。在监听这个消息的时候需要注意1. 无论是插入还是拔出都会有这个消息。 2. 当设备插入或者拔出的时候,windows 系统会在很短的时间里触发大量这个消息,所以在处理这个消息的时候需要注意。 DBT_DEVICEARRIVAL,DBT_DEVICEREMOVECOMPLETE 虽然也可以监视这两个消息,但是据我的经验,这两个消息有时候不会触发。原因还不知道,所以保险起见就用WM_DEVICECHANGE


    2) mac osx

        由于mac osx usb 机制并不清楚,所以采用一种比较笨的方法,启动一个线程,每隔一秒扫描一次usb设备列表。目前使用到了libusb 这个开源库来扫描的USB设备。使用很简单


二 判断一个设备是否是手机

      对于插入的手机来说都有一个VID,PID信息,大部分情况下根据这个VID,PID来判断是否是一个手机。可以从设备管理器查看到当前连接设备的VID,PID



     

那如何获取这个VID,PID呢。在windows 系统上可以使用setupxxxx 函数,mac 系统上使用开源的libusb。windows系统上在枚举USB 设备的时候有比较多需要注意的问题。

        1)。 插入一个USB 设备,在设备管理器中会出现多个设备。这些设备可以认为是USB 的子节点。除了会有一个Android Phone 节点之外,一般都还有一个便携设备,还有一个USB 设备。在打开USB 调试的情况下一个手机一般有3个节点。一个Android Phone,一个便携设备,一个USB 节点。没有打开调试的时候可能就只有2个节点。所以在枚举的时候就需要确立好这些子节点是属于哪个USB 设备的。否则你就不知道当前插入了几个手机了,因为这个时候有3个VID,PID。那到底是插入了3个设备还是1个设备呢。这里就需要确定子节点是属于哪个USB 设备的。

下面的代码用来枚举所有的设备,并且把每一类设备归类

Windows 代码如下:

struct USBDeviceInfo
{
XString strVID;
XString strPID;


//显示的名称
XString strShowName;
//硬件ID,会有多个
std::vector<XString> hardIDVect;
//设备标识,
XString strDeviceIdentify;
//设备状态
int iStatus;
//USB 设备会有多个子节点,保存子节点的设备表示,目前windows 下有用
std::list<boost::shared_ptr<USBDeviceInfo> >childDeviceInfo;
    USBDeviceInfo()
    {
        iStatus = 0;
    }
};



HDEVINFOhDevInfo = INVALID_HANDLE_VALUE;
std::map<XString, std::list<boost::shared_ptr<USBDeviceInfo> > >devMap;
//针对USB 设备,子节点到父节点 interfaceid 对照表
std::map<XString, XString> childInterfaceToParentInterfactID;
do 
{
hDevInfo = SetupDiGetClassDevs(0L, 0L, NULL, DIGCF_PRESENT |
DIGCF_ALLCLASSES | DIGCF_PROFILE);
//打开设备列表
if (hDevInfo == INVALID_HANDLE_VALUE)
{
break;
}


//循环枚举设备
int iIndex = 0;
SP_DEVINFO_DATA spDevInfoData = { 0 };
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
while (TRUE)
{
std::wstring wstrParentNodeName;
if (!SetupDiEnumDeviceInfo(hDevInfo,
iIndex,
&spDevInfoData))
{
break;
}
wchar_t  szBuf[1024] = { 0 };


if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
&spDevInfoData,
SPDRP_CLASS, //SPDRP_DEVICEDESC,
0L,
(PBYTE)szBuf,
1023 * sizeof(wchar_t),
0))
{
wcscpy(szBuf, L"Unknow");
}
wstrParentNodeName = szBuf;


//判断下是否已经存在了这个父节点
std::map<std::wstring, std::list<boost::shared_ptr<USBDeviceInfo> > >::iterator it = devMap.find(wstrParentNodeName);
if (it == devMap.end())
{
devMap[szBuf] = std::list<boost::shared_ptr<USBDeviceInfo> >();
it = devMap.find(szBuf);
}
boost::shared_ptr<USBDeviceInfo> pPtr(new USBDeviceInfo);
//获取VID,PID
XString strInstanceID;
GetDeviceInstanceId(hDevInfo, spDevInfoData, strInstanceID);
CRegHelp::GetVid(strInstanceID, pPtr->strVID);
CRegHelp::GetPid(strInstanceID, pPtr->strPID);
//获取显示的名称
szBuf[0] = 0;
if (SetupDiGetDeviceRegistryProperty(hDevInfo,
&spDevInfoData,
SPDRP_FRIENDLYNAME,
0L,
(PBYTE)szBuf,
1023 * sizeof(wchar_t),
0))
{


}
else if (SetupDiGetDeviceRegistryProperty(hDevInfo,
&spDevInfoData,
SPDRP_DEVICEDESC,
0L,
(PBYTE)szBuf,
1023 * sizeof(wchar_t),
0))
{


}
else
{


}
pPtr->strShowName = szBuf;
//硬件ID
szBuf[0] = 0;
if (SetupDiGetDeviceRegistryProperty(hDevInfo,
&spDevInfoData,
SPDRP_HARDWAREID,
0L,
(PBYTE)szBuf,
1023 * sizeof(wchar_t),
0))
{
SpliteString(szBuf, pPtr->hardIDVect);
}



//获取设备的接口ID,以及可能的ADB名字
szBuf[0] = 0;
std::vector<XString> compatibleIDS;
if (SetupDiGetDeviceRegistryProperty(hDevInfo,
&spDevInfoData,
SPDRP_COMPATIBLEIDS,
0L,
(PBYTE)szBuf,
1023 * sizeof(wchar_t),
0))
{
SpliteString(szBuf, compatibleIDS);
}
XString strInterfaceID;
GetDeviceInterfaceInfo(hDevInfo, spDevInfoData, strInterfaceID);
XString strDeviceIdentify;
CRegHelp::GetInterfaceIdentify(strInterfaceID, strDeviceIdentify);
pPtr->strDeviceIdentify = boost::to_upper_copy(strDeviceIdentify);

//设备状态
DWORD dwDevStatus = 0;
DWORD dwProblem = 0;
CM_Get_DevNode_Status(&dwDevStatus, &dwProblem, spDevInfoData.DevInst, 0);
pPtr->iStatus = dwProblem;
//如果是USB 的设备,需要把子节点也枚举出来
if (wstrParentNodeName == __XT("USB"))
{
//获取子实例
DEVINST childInst = 0;
DEVINST devInst = 0;
if (CR_SUCCESS == CM_Get_Child(&childInst, spDevInfoData.DevInst, 0))
{
do
{
wchar_t buffer[0x400] = { 0 };
if (CM_Get_Device_ID(childInst, buffer, 0x400, 0) == 0)
{
std::wstring wstrChild = buffer;
if (!wstrChild.empty())
{
XString strChildVID;
XString strChildPID;
CRegHelp::GetVid(wstrChild, strChildVID);
CRegHelp::GetPid(wstrChild, strChildPID);
if ((boost::iequals(strChildVID,pPtr->strVID))
&& (boost::iequals(strChildPID,pPtr->strPID))
&& (strChildPID != __XT(""))
&& (strChildVID != __XT("")))
{
XString childIdentify;
CRegHelp::GetDeviceIdentifyFromInstancePath(wstrChild, childIdentify);
boost::shared_ptr<USBDeviceInfo> childDevice(new USBDeviceInfo);
childDevice->strDeviceIdentify = boost::to_upper_copy(childIdentify);
pPtr->childDeviceInfo.push_back(childDevice);
}
}
}
devInst = childInst;
} while (CR_SUCCESS == CM_Get_Sibling(&childInst, devInst, 0));
}
}
if ((pPtr->strVID != __XT(""))
&& (pPtr->strPID != __XT("")))
{
it->second.push_back(pPtr);
}
iIndex++;
}
} while (0);
if (hDevInfo != INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(hDevInfo);
}

MAC OSX代码如下:

 int iRet = libusb_init(NULL);
    if (iRet < 0) {
        return false;
    }
    libusb_device **devs;
    ssize_t count = libusb_get_device_list(NULL, &devs);
    if (count > 0) {
        libusb_device *dev = NULL;
        int i = 0;
        char buffer[20] = {0};
        while ((dev = devs[i++]) != NULL) {
            struct libusb_device_descriptor desc;
            int r = libusb_get_device_descriptor(dev, &desc);
            if (r < 0) {
                continue;
            }
            boost::shared_ptr<USBDeviceInfo> pPtr(new USBDeviceInfo);
            sprintf(buffer, "%04X",desc.idVendor);
            pPtr->strVID = buffer;
            
            sprintf(buffer, "%04X",desc.idProduct);
            pPtr->strPID = buffer;
            usbDeviceList.push_back(pPtr);


int iBusNumber = libusb_get_bus_number(dev);
int iDeviceAddress = libusb_get_device_address(dev);
XStringStream strTmpStream;
strTmpStream << iBusNumber <<"&"<< iDeviceAddress;

pPtr->strDeviceIdentify = CCryptUtil::MD5(strTmpStream.str());

        }  
        libusb_free_device_list(devs, 1);
    }
    libusb_exit(NULL);

以上部分代码会枚举所有的设备,并且把子节点和父节点的对应关系记录下来,所以接下来只需要枚举一次所有的USB 节点,替换真正的子节点的信息了。

        上面仅仅是枚举到了系统的USB 设备,要判断哪个是插入哪个是拔出的还需要再一个步骤。起始比较简单的,记录两个状态就可以。 上一次扫描USB 列表,以及这次的USB 列表。这两个列表做一个比对就可以了。比如上次没有的设备,这次枚举到了,说明是新增加的设备。

       如果手机打开了调试,但是没有安装驱动的话,那就会出现一个未知设备,在设备管理器可以看到是一个“?”标识的设备。




下载地址:

http://115.29.237.15:8080/MobileAssist/Product/MobileTools.7z


QQ:2506314894



0 0
原创粉丝点击