近期學了一點Python,然後正好有一個手機同步工具方面的預研工作要完成。
要實現PC與手機的通訊,首先要找到他們的通訊協議,還好的是Android有完善的協議:ADB
ADB的程式碼是開源的,而且支援Windows平臺,有現成的DLL可以呼叫:AdbWinApi.dll,AdbWinUsbApi.dll
好了,可以用VC搞定,但我想用Python試一下,於是開始了苦逼的查資料+實驗的過程。
實驗過程就不多說了,由於上面的兩個DLL都是用C實現的,提供的標頭檔案也是C語言的,所以有了下面這個python測試程式(Python2.7):
import ctypes #自定義的GUID結構,有興趣的可以自己研究用uuid模組 class GUID(ctypes.Structure): _fields_ = [("Data1", ctypes.c_ulong), ("Data2", ctypes.c_ushort), ("Data3", ctypes.c_ushort), ("Data4", ctypes.c_ubyte*8)] #自己定義的一個結構體,便於使用DLL介面 class AdbInterfaceInfo(ctypes.Structure): _fields_ = [("class_id", GUID), ("flags", ctypes.c_ulong), ("device_name", ctypes.c_wchar*800)] def strGUID(GUID): string = '' string = string + '%x' % buff.class_id.Data1 + '-%x' % buff.class_id.Data2 + '-%x' % buff.class_id.Data3 string = string + '-%x' % buff.class_id.Data4[0] string = string + '%x' % buff.class_id.Data4[1] string = string + '%x' % buff.class_id.Data4[2] string = string + '%x' % buff.class_id.Data4[3] string = string + '%x' % buff.class_id.Data4[4] string = string + '%x' % buff.class_id.Data4[5] string = string + '%x' % buff.class_id.Data4[6] string = string + '%x' % buff.class_id.Data4[7] return string dll = ctypes.cdll.LoadLibrary('AdbWinApi.dll') usb_class_id = GUID(0xF72FE0D4, 0xCBCB, 0x407d, (0x88, 0x14, 0x9e, 0xd6, 0x73, 0xd0, 0xdd, 0x6b)) enum_handle = dll.AdbEnumInterfaces(usb_class_id, ctypes.c_bool('true'), ctypes.c_bool('true'), ctypes.c_bool('true')) while(1): buff = AdbInterfaceInfo() size = ctypes.c_ulong(ctypes.sizeof(buff)) status = dll.AdbNextInterface(enum_handle, ctypes.byref(buff), ctypes.byref(size)) if status==1: #print "GUID = " + strGUID(buff.class_id) #print "status = " + str(status) #print "Name = " + str(buff.device_name) hAdbApi = dll.AdbCreateInterfaceByName(buff.device_name); if hAdbApi == 0: print 'AdbCreateInterfaceByName Fail' else: serial = ' '*128 pserial = ctypes.c_char_p() pserial.value = serial serial_len = ctypes.c_ulong(len(serial)) ret = dll.AdbGetSerialNumber(hAdbApi, pserial, ctypes.byref(serial_len), ctypes.c_bool('false')); if ret == 1: print 'Device Name: ' + '%s'% serial else: print 'Get Device Name Fail' else: print 'Finished' break import ctypes #自定義的GUID結構,有興趣的可以自己研究用uuid模組 class GUID(ctypes.Structure): _fields_ = [("Data1", ctypes.c_ulong), ("Data2", ctypes.c_ushort), ("Data3", ctypes.c_ushort), ("Data4", ctypes.c_ubyte*8)] #自己定義的一個結構體,便於使用DLL介面 class AdbInterfaceInfo(ctypes.Structure): _fields_ = [("class_id", GUID), ("flags", ctypes.c_ulong), ("device_name", ctypes.c_wchar*800)] def strGUID(GUID): string = '' string = string + '%x' % buff.class_id.Data1 + '-%x' % buff.class_id.Data2 + '-%x' % buff.class_id.Data3 string = string + '-%x' % buff.class_id.Data4[0] string = string + '%x' % buff.class_id.Data4[1] string = string + '%x' % buff.class_id.Data4[2] string = string + '%x' % buff.class_id.Data4[3] string = string + '%x' % buff.class_id.Data4[4] string = string + '%x' % buff.class_id.Data4[5] string = string + '%x' % buff.class_id.Data4[6] string = string + '%x' % buff.class_id.Data4[7] return string dll = ctypes.cdll.LoadLibrary('AdbWinApi.dll') usb_class_id = GUID(0xF72FE0D4, 0xCBCB, 0x407d, (0x88, 0x14, 0x9e, 0xd6, 0x73, 0xd0, 0xdd, 0x6b)) enum_handle = dll.AdbEnumInterfaces(usb_class_id, ctypes.c_bool('true'), ctypes.c_bool('true'), ctypes.c_bool('true')) while(1): buff = AdbInterfaceInfo() size = ctypes.c_ulong(ctypes.sizeof(buff)) status = dll.AdbNextInterface(enum_handle, ctypes.byref(buff), ctypes.byref(size)) if status==1: #print "GUID = " + strGUID(buff.class_id) #print "status = " + str(status) #print "Name = " + str(buff.device_name) hAdbApi = dll.AdbCreateInterfaceByName(buff.device_name); if hAdbApi == 0: print 'AdbCreateInterfaceByName Fail' else: serial = ' '*128 pserial = ctypes.c_char_p() pserial.value = serial serial_len = ctypes.c_ulong(len(serial)) ret = dll.AdbGetSerialNumber(hAdbApi, pserial, ctypes.byref(serial_len), ctypes.c_bool('false')); if ret == 1: print 'Device Name: ' + '%s'% serial else: print 'Get Device Name Fail' else: print 'Finished' break
上面這個簡單的Python程式碼,可以透過AdbWinApi.dll和AdbWinUsbApi.dll這兩個DLL來找到你PC上正連線著的Android裝置。
只呼叫了3個DLL介面,但目的已經達到,可以得出下面的結論:
使用Python呼叫DLL的方式來實現ADB工具是可行的,當然麻煩是不會少的了。
寫在最後,Python呼叫C寫的DLL還是比較麻煩的,特別是引數傳遞,尤其是指標的處理,這方面還得依靠ctypes模組。。。