如何从python代码中直接访问Android的Service

 在Kivy中,通过pyjnius扩展可以间接调用Java代码,而pyjnius利用的是Java的反射机制。但是在Python对象和Java对象中转来转去总让人感觉到十分别扭。好在android提供了binder这个进程间通信的功能,Java中的Service也是基于Binder的C++代码封装来实现进程间通信的,这也为从Python代码中绕开pyjnius直接访问Java代码提供了可能,既然Java的Service是基于C++的封装来实现的,也同样可以在Python中封装同样的C++代码,这篇文章讲解了如何通过binder在Python代码中直接访问Java的Service,如WifiService。

专业从事成都网站建设、成都网站制作,高端网站制作设计,小程序制作,网站推广的成都做网站的公司。优秀技术团队竭力真诚服务,采用H5网站设计+CSS3前端渲染技术,响应式网站建设,让网站在手机、平板、PC、微信下都能呈现。建站过程建立专项小组,与您实时在线互动,随时提供解决方案,畅聊想法和感受。

binder_wrap.h

#ifndef BINDER_WRAP_H  
#define BINDER_WRAP_H  
  
  
#ifdef __cplusplus  
extern "C" {  
#endif  
  
typedef int (*vector_visitor)(const char16_t* str16,int length,void *data);  
typedef int (*fnOnTransact)(uint32_t code,const void *data,void *reply,uint32_t flags,void *userData);  
int server_create(const char *name,const char *descriptor,fnOnTransact onTrans,void *data);  
  
void* binder_getbinder(const char *name);  
int binder_releasebinder(void* binder);  
int binder_listServices(vector_visitor visitor,void *data);  
int binder_getInterfaceDescriptor(void *binder,char16_t *descriptor,size_t size);  
int binder_transact(void* binder,int code,const void *data,void* reply,int flags);  
void* parcel_new();  
int parcel_destroy(void* parcel);  
int parcel_writeInterfaceToken(void* parcel,const char *interface);  
int parcel_writeInt32(void *parcel,int val);  
int parcel_writeCString(void *parcel,const char* str);  
int parcel_writeString16(void *parcel,const char16_t* str, size_t len);  
  
int parcel_readInt32(void *parcel);  
long parcel_readInt64(void *parcel);  
int parcel_readString16(void *parcel,char16_t* str, size_t len);  
int parcel_readInplace(void *parcel,void* data, int len);  
int parcel_readExceptionCode(void *parcel);  
int parcel_dataAvail(void *parcel);  
  
#ifdef __cplusplus  
}  
#endif  
  
#endif

binder_wrap.cpp

#include   
#include   
#include   
  
#include   
#include   
#include   
#include   
  
#include   
  
#include "binder_wrap.h"  
  
using namespace android;  
  
void* binder_getbinder(const char *name)  
{  
    android::sp sm = android::defaultServiceManager();  
    sp *binder = new sp();  
    do {  
        *binder = sm->getService(android::String16(name));  
        if (binder != 0)  
        {  
            break;  
        }  
        usleep(500000); // 0.5 s  
    } while(true);  
    return reinterpret_cast(binder);  
}  
  
int binder_releasebinder(void* binder)  
{  
    sp *bp = reinterpret_cast *>(binder);  
  
    if(bp == 0)  
    {  
        return 0;  
    }  
  
    delete bp;  
      
    return 1;  
}  
  
//Vector    listServices() = 0;  
int binder_listServices(vector_visitor visitor,void *data)  
{  
    android::sp sm = android::defaultServiceManager();  
  
    Vector list = sm->listServices();  
  
    for (int i=0;i *bp = reinterpret_cast *>(binder);  
  
    if(bp == 0)  
    {  
        return 0;  
    }  
      
    if (descriptor == NULL || size <= 0)  
    {  
        return 0;  
    }  
      
    String16 des = (*bp)->getInterfaceDescriptor();  
  
    if (size > des.size())  
    {  
        size = des.size();  
    }  
  
    memcpy(descriptor,des.string(),size*2);  
  
    return size;  
}  
  
//int binder_transact(void* binder,int code,const Parcel& data,Parcel* reply,int flags = 0)  
int binder_transact(void* binder,int code,const void *data,void* reply,int flags)  
{  
    sp *bp = reinterpret_cast *>(binder);  
   
    if(bp == 0 || data == 0 || reply == 0)  
    {  
        return 0;  
    }  
    return (*bp)->transact(code,*(Parcel*)data,(Parcel*)reply,flags);  
}  
  
void* parcel_new()  
{  
    return (void*)new Parcel();  
}  
  
int parcel_destroy(void* parcel)  
{  
    if(parcel == 0)  
    {  
        return 0;  
    }  
    delete (Parcel*)parcel;  
    return 1;  
}  
  
int parcel_writeInterfaceToken(void* parcel,const char *interface)  
{  
    Parcel *p = reinterpret_cast(parcel);  
      
    if(p == 0)  
    {  
        return 0;  
    }  
    return p->writeInterfaceToken(String16(interface));  
}  
  
int parcel_writeInt32(void *parcel,int val)  
{  
    Parcel *p = reinterpret_cast(parcel);  
      
    if(p == 0)  
    {  
        return 0;  
    }  
  
    return p->writeInt32(val);  
}  
  
int parcel_writeCString(void *parcel,const char* str)  
{  
    Parcel *p = reinterpret_cast(parcel);  
  
    if(p == 0)  
    {  
        return 0;  
    }  
    return p->writeCString(str);  
}  
  
int parcel_writeString16(void *parcel,const char16_t* str, size_t len)  
{  
    Parcel *p = reinterpret_cast(parcel);  
      
    if(p == 0)  
    {  
        return 0;  
    }  
      
    if (str == 0 || len <= 0)  
    {  
        return 0;  
    }  
      
    return p->writeString16(str,len);  
}  
  
  
int parcel_readInt32(void *parcel)  
{  
    Parcel *p = reinterpret_cast(parcel);  
      
    if(p == 0)  
    {  
        return 0;  
    }  
    return p->readInt32();  
}  
  
long parcel_readInt64(void *parcel)  
{  
    Parcel *p = reinterpret_cast(parcel);  
  
    if(p == 0)  
    {  
        return 0;  
    }  
    return p->readInt64();  
}  
  
int parcel_readString16(void *parcel,char16_t* str, size_t len)  
{  
    Parcel *p = reinterpret_cast(parcel);  
  
    if(p == 0)  
    {  
        return 0;  
    }  
  
    if (str == NULL || len <= 0)  
    {  
        return 0;  
    }  
      
    String16 str16 = p->readString16();  
      
    if (len > str16.size())  
    {  
        len = str16.size();  
    }  
      
    memcpy(str,str16.string(),len*2);  
  
    return len;  
}  
  
int parcel_readExceptionCode(void *parcel)  
{  
    Parcel *p = reinterpret_cast(parcel);  
  
    if(p == 0)  
    {  
        return 0;  
    }  
    return p->readExceptionCode();  
}  
  
  
int parcel_readInplace(void *parcel,void* data, int len)  
{  
    Parcel *p = reinterpret_cast(parcel);  
  
    if(p == 0)  
    {  
        return 0;  
    }  
  
    if (len >= 0 && len <= (int32_t)p->dataAvail())  
    {  
        const void *d = p->readInplace(len);  
        memcpy(data,d,len);  
        return len;  
    }  
    return 0;  
}  
  
int parcel_dataAvail(void *parcel)  
{  
    Parcel *p = reinterpret_cast(parcel);  
  
    if(p == 0)  
    {  
        return 0;  
    }  
  
    return p->dataAvail();  
      
}

正如代码中所示,这里对C++的IBinder和Parcel两个对象进行了封装,而Java的Service的底层实现也正是对这两个类进行封装的结果,具体的可以看

frameworks\base\core\jni\android_util_Binder.cpp

的代码,

再来看下如何在Python中使用这些代码,这里用cython来封装这些C接口:

binder.pyx

cdef extern from "utils/Unicode.h":  
    ctypedef short char16_t  
    ctypedef unsigned int uint32_t  
  
cdef extern from "Python.h":  
    ctypedef short Py_UNICODE  
    ctypedef size_t Py_ssize_t  
    object PyString_FromStringAndSize(const char *v, Py_ssize_t len)   
    int PyString_AsStringAndSize(object obj, char **buffer, Py_ssize_t *length)   
    object PyUnicode_FromUnicode(const Py_UNICODE *u, Py_ssize_t size)   
    Py_UNICODE* PyUnicode_AS_UNICODE(object)  
    Py_ssize_t PyUnicode_GetSize(object)  
    void Py_INCREF(object)  
    void Py_DECREF(object)  
  
cdef extern from "binder_wrap.h":  
    ctypedef int (*vector_visitor)(const char16_t* str16,int length,void *data)  
    int binder_listServices(vector_visitor visitor,void *data)  
    ctypedef int (*fnOnTransact)(uint32_t code,const void *data,void *reply,uint32_t flags,void *userData)  
    int server_create(const char *name,const char *descriptor,fnOnTransact onTrans,void *data)  
    void* binder_getbinder(const char *name)  
    int binder_releasebinder(void* binder)  
    int binder_getInterfaceDescriptor(void *binder,char16_t *descriptor,int size)  
    int binder_transact(void* binder,int code,const void *data,void* reply,int flags)  
  
    void* parcel_new()  
    int parcel_destroy(void* parcel)  
    int parcel_writeInterfaceToken(void* parcel,const char *interface)  
    int parcel_writeInt32(void *parcel,int val)  
    int parcel_writeCString(void *parcel,const char* str)  
    int parcel_writeString16(void *parcel,const char16_t* str, size_t len)  
  
    int parcel_readInt32(void *parcel)  
    int parcel_readInt64(void *parcel)  
    int parcel_readString16(void *parcel,char16_t* str, size_t len)  
    int parcel_readExceptionCode(void *parcel)  
    int parcel_readInplace(void *parcel,void* data, int len)  
  
    int parcel_dataAvail(void *parcel)  
  
  
cdef int visitor(const char16_t* str16,int length,void *data):  
    arr = data  
    o = PyUnicode_FromUnicode(str16,length)  
    arr.append(o)  
      
def listServices():  
    arr = []  
    Py_INCREF(arr)  
    binder_listServices(visitor,arr)  
    Py_DECREF(arr)  
    return arr  
  
cdef class Binder:  
    cdef void *ptr  
    def __cinit__(self,char *name): #, sp[IBinder] service):  
        self.ptr = binder_getbinder(name)  
  
    def __dealloc__(self):  
        binder_releasebinder(self.ptr)  
  
    def getInterfaceDescriptor(self):  
        cdef char16_t descriptor[256]  
        cdef int ret  
        ret = binder_getInterfaceDescriptor(self.ptr,descriptor,sizeof(descriptor))  
        if not ret:  
            return None  
        return PyUnicode_FromUnicode(descriptor,ret)  
  
    def transact(self,int code,data,reply,int flags):  
        cdef int dataPtr = data.getNativePtr()  
        cdef int replyPtr = reply.getNativePtr()  
        binder_transact(self.ptr,code,dataPtr,replyPtr,flags)  
        return reply  
  
cdef class Parcel:  
    cdef void *ptr  
    cdef int nativePtr  
    def __cinit__(self,unsigned int nativePtr=0): #, sp[IBinder] service):  
        self.nativePtr = nativePtr  
        if not nativePtr:  
            self.ptr = parcel_new()  
        else:  
            self.ptr = nativePtr  
  
    def __dealloc__(self):  
        if not self.nativePtr:  
            parcel_destroy(self.ptr)  
  
    def getNativePtr(self):  
        return self.ptr  
  
    def writeInterfaceToken(self,const char *interface):  
        return parcel_writeInterfaceToken(self.ptr,interface)  
  
    def writeInt(self,int val):  
        self.writeInt32(val)  
    def writeInt32(self,int val):  
        return parcel_writeInt32(self.ptr,val)  
  
    def writeCString(self,const char* cstr):  
        return parcel_writeCString(self.ptr,cstr)  
  
    def writeString16(self,ustr):  
        cdef char16_t *un  
        cdef int size  
        if isinstance(ustr,unicode):  
            un = PyUnicode_AS_UNICODE(ustr)  
            size = PyUnicode_GetSize(ustr)  
            return parcel_writeString16(self.ptr,un,size)  
  
    def readInt32(self):  
        return parcel_readInt32(self.ptr)  
    def readInt(self):  
        return self.readInt32()  
  
    def readInt64(self):  
        return parcel_readInt64(self.ptr)  
  
    def readExceptionCode(self):  
        return parcel_readExceptionCode(self.ptr)  
  
    def readString16(self):  
        cdef char16_t str16[256]  
        cdef int ret  
        ret = parcel_readString16(self.ptr,str16,sizeof(str16))  
        if not ret:  
            return None  
        return PyUnicode_FromUnicode(str16,ret)  
  
    def readByteArray(self):  
        return self.createByteArray()  
  
    def createByteArray(self):  
        length = self.readInt()  
        print 'createByteArray:',length  
        return self.readInplace(length)  
  
#    int parcel_readInplace(void *parcel,void* data, size_t len)  
    def readInplace(self,length):  
        cdef char arr[512]  
        ret = parcel_readInplace(self.ptr,arr,length)  
        if ret == length:  
            return PyString_FromStringAndSize(arr,length)  
        else:  
            return None  
  
#    int parcel_dataAvail(void *parcel)  
    def dataAvail(self):  
        return parcel_dataAvail(self.ptr)  
  
    def createTypedArrayList(self,creator):  
        N = self.readInt()  
        if N <= 0:  
            return None  
        arr = []  
        for i in range(N):  
            if self.readInt() == 0:  
                continue  
            else:  
                result = creator.createFromParcel(self)  
                arr.append(result)  
        return arr  
 
    @classmethod  
    def obtain(cls):  
        return Parcel()  
    @classmethod  
    def recycle(cls):  
        pass

好,再来看看如何来实现访问WifiService的功能:

WifiService.py

from binder import Binder,Parcel  
  
WIFI_SERVICE = "wifi";  
DESCRIPTOR = "android.net.wifi.IWifiManager";  
FIRST_CALL_TRANSACTION = 1  
TRANSACTION_getConfiguredNetworks = (FIRST_CALL_TRANSACTION + 0);  
TRANSACTION_addOrUpdateNetwork = (FIRST_CALL_TRANSACTION + 1);  
TRANSACTION_removeNetwork = (FIRST_CALL_TRANSACTION + 2);  
TRANSACTION_enableNetwork = (FIRST_CALL_TRANSACTION + 3);  
TRANSACTION_disableNetwork = (FIRST_CALL_TRANSACTION + 4);  
TRANSACTION_pingSupplicant = (FIRST_CALL_TRANSACTION + 5);  
TRANSACTION_startScan = (FIRST_CALL_TRANSACTION + 6);  
TRANSACTION_getScanResults = (FIRST_CALL_TRANSACTION + 7);  
TRANSACTION_disconnect = (FIRST_CALL_TRANSACTION + 8);  
TRANSACTION_reconnect = (FIRST_CALL_TRANSACTION + 9);  
TRANSACTION_reassociate = (FIRST_CALL_TRANSACTION + 10);  
TRANSACTION_getConnectionInfo = (FIRST_CALL_TRANSACTION + 11);  
TRANSACTION_setWifiEnabled = (FIRST_CALL_TRANSACTION + 12);  
TRANSACTION_getWifiEnabledState = (FIRST_CALL_TRANSACTION + 13);  
TRANSACTION_setCountryCode = (FIRST_CALL_TRANSACTION + 14);  
TRANSACTION_setFrequencyBand = (FIRST_CALL_TRANSACTION + 15);  
TRANSACTION_getFrequencyBand = (FIRST_CALL_TRANSACTION + 16);  
TRANSACTION_isDualBandSupported = (FIRST_CALL_TRANSACTION + 17);  
TRANSACTION_saveConfiguration = (FIRST_CALL_TRANSACTION + 18);  
TRANSACTION_getDhcpInfo = (FIRST_CALL_TRANSACTION + 19);  
TRANSACTION_acquireWifiLock = (FIRST_CALL_TRANSACTION + 20);  
TRANSACTION_updateWifiLockWorkSource = (FIRST_CALL_TRANSACTION + 21);  
TRANSACTION_releaseWifiLock = (FIRST_CALL_TRANSACTION + 22);  
TRANSACTION_initializeMulticastFiltering = (FIRST_CALL_TRANSACTION + 23);  
TRANSACTION_isMulticastEnabled = (FIRST_CALL_TRANSACTION + 24);  
TRANSACTION_acquireMulticastLock = (FIRST_CALL_TRANSACTION + 25);  
TRANSACTION_releaseMulticastLock = (FIRST_CALL_TRANSACTION + 26);  
TRANSACTION_setWifiApEnabled = (FIRST_CALL_TRANSACTION + 27);  
TRANSACTION_getWifiApEnabledState = (FIRST_CALL_TRANSACTION + 28);  
TRANSACTION_getWifiApConfiguration = (FIRST_CALL_TRANSACTION + 29);  
TRANSACTION_setWifiApConfiguration = (FIRST_CALL_TRANSACTION + 30);  
TRANSACTION_startWifi = (FIRST_CALL_TRANSACTION + 31);  
TRANSACTION_stopWifi = (FIRST_CALL_TRANSACTION + 32);  
TRANSACTION_addToBlacklist = (FIRST_CALL_TRANSACTION + 33);  
TRANSACTION_clearBlacklist = (FIRST_CALL_TRANSACTION + 34);  
TRANSACTION_getWifiServiceMessenger = (FIRST_CALL_TRANSACTION + 35);  
TRANSACTION_getWifiStateMachineMessenger = (FIRST_CALL_TRANSACTION + 36);  
TRANSACTION_getConfigFile = (FIRST_CALL_TRANSACTION + 37);  
TRANSACTION_captivePortalCheckComplete = (FIRST_CALL_TRANSACTION + 38);  
  
mRemote = Binder(WIFI_SERVICE)  
  
def transact(TRANSACTION):  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    mRemote.transact(TRANSACTION, _data, _reply, 0)  
    _reply.readExceptionCode()  
    return _reply.readInt32()  
  
def getConfiguredNetworks():  
    pass  
def addOrUpdateNetwork():  
    pass  
def removeNetwork():  
    pass  
def enableNetwork(netId,disableOthers):  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    _data.writeInt32(netId)  
    if disableOthers:  
        _data.writeInt32(1)  
    else:  
        _data.writeInt32(0)  
    mRemote.transact(TRANSACTION_enableNetwork, _data, _reply, 0)  
    _reply.readExceptionCode()  
    return _reply.readInt32() != 0  
def disableNetwork(netId):  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    _data.writeInt32(netId)  
    mRemote.transact(TRANSACTION_disableNetwork, _data, _reply, 0)  
    _reply.readExceptionCode()  
    return _reply.readInt32() != 0  
  
def pingSupplicant():  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    mRemote.transact(TRANSACTION_pingSupplicant, _data, _reply, 0)  
    _reply.readExceptionCode()  
    return _reply.readInt32() != 0  
  
def startScan(forceActive):  
    _data = Parcel()  
    _reply = Parcel()  
    ret = 0  
    try:  
        _data.writeInterfaceToken(DESCRIPTOR)  
        if forceActive:  
            _data.writeInt(1)  
        else:  
            _data.writeInt(0)  
        mRemote.transact(TRANSACTION_startScan, _data, _reply, 0)  
        ret = _reply.readExceptionCode()  
    finally:  
        _reply.recycle()  
        _data.recycle()  
    return ret == 0  
  
class ScanResult:  
    def __init__(self,ssid,bssid,caps,level,frequency,timestamp):  
        self.ssid = ssid  
        self.bssid = bssid  
        self.caps = caps  
        self.level = level  
        self.frequency = frequency  
        self.timestamp = timestamp  
    @classmethod  
    def createFromParcel(cls,reply):  
        has_ssid = reply.readInt32()  
        ssid = None  
        if has_ssid:  
            ssid_lengt = reply.readInt()  
            ssid = reply.readByteArray()  
        BSSID = reply.readString16()  
        caps = reply.readString16()  
        level = reply.readInt()  
        frequency = reply.readInt()  
        timestamp = reply.readInt64()  
          
        print 'BSSID:',BSSID      
        print 'caps:',caps  
        print 'level:',level  
        print 'frequency:',frequency  
        print 'timestamp:',timestamp  
        return ScanResult(ssid,BSSID,caps,level,frequency,timestamp)  
  
def getScanResults():  
    _data = Parcel.obtain()  
    _reply = Parcel.obtain()  
    _result = None  
    try:  
        _data.writeInterfaceToken(DESCRIPTOR)  
        mRemote.transact(TRANSACTION_getScanResults, _data, _reply, 0)  
        if 0 != _reply.readExceptionCode():  
            return None  
        _result = _reply.createTypedArrayList(ScanResult)  
    finally:  
        _reply.recycle()  
        _data.recycle()  
    return _result  
  
def disconnect():  
    return transact(TRANSACTION_disconnect) != 0  
  
def reconnect():  
    return transact(TRANSACTION_reconnect) != 0  
  
def reassociate():  
    return transact(TRANSACTION_reassociate) != 0  
  
""" 
class WifiInfo: 
    def __init__(): 
        pass 
    @classmethod 
    def createFromParcel(cls,r): 
        info = WifiInfo(); 
        info.networkId  = r.readInt32() 
        info.rssi = r.readInt32() 
        info.linkSpeed = r.readInt32() 
        if r.readByte() == 1: 
            info.setInetAddress(InetAddress.getByAddress(in.createByteArray())) 
        if r.readInt() == 1: 
            info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(r) 
        info.mBSSID = r.readString16() 
        info.mMacAddress = r.readString16() 
        info.mMeteredHint = r.readInt32() != 0 
"""  
  
def getConnectionInfo():  
    pass  
def setWifiEnabled(enable):  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    if enable:  
        _data.writeInt32(1)  
    else:  
        _data.writeInt32(0)  
    mRemote.transact(TRANSACTION_setWifiEnabled, _data,_reply,0)  
    _reply.readExceptionCode()  
    _result = (0!=_reply.readInt32())  
    return _result;  
  
def getWifiEnabledState():  
    return transact(TRANSACTION_getWifiEnabledState)  
      
def setCountryCode(country,persist):  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    if isinstance(country,str):  
        country = unicode(contry)  
    _data.writeString16(country)  
    if persist:  
        _data.writeInt32(1)  
    else:  
        _data.writeInt32(0)  
    mRemote.transact(TRANSACTION_setCountryCode, _data,_reply,0)  
    _reply.readExceptionCode()  
    _result = (0!=_reply.readInt32())  
    return _result;  
      
def setFrequencyBand(band, persist):  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    if isinstance(country,str):  
        country = unicode(contry)  
    _data.writeInt32(band)  
    if persist:  
        _data.writeInt32(1)  
    else:  
        _data.writeInt32(0)  
    mRemote.transact(TRANSACTION_setFrequencyBand, _data,_reply,0)  
    _reply.readExceptionCode()  
    _result = (0!=_reply.readInt32())  
    return _result;  
  
def getFrequencyBand():  
    return transact(TRANSACTION_getFrequencyBand)  
  
def isDualBandSupported():  
    return transact(TRANSACTION_isDualBandSupported) != 0  
def saveConfiguration():  
    pass  
  
def get_readable_address(addr):  
    return "%d:%d:%d:%d"%(addr&0xff,(addr>>8)&0xff,(addr>>16)&0xff,(addr>>24)&0xff)  
  
def getDhcpInfo():  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    mRemote.transact(TRANSACTION_getDhcpInfo, _data,_reply,0)  
    _reply.readExceptionCode()  
    if 0 == _reply.readInt32():  
        return None  
  
    ipAddress = get_readable_address(reply.readInt32());  
    gateway = get_readable_address(reply.readInt32());  
    netmask = get_readable_address(reply.readInt32());  
    DNS1 = get_readable_address(reply.readInt32());  
    dns2 = get_readable_address(reply.readInt32());  
    serverAddress = get_readable_address(reply.readInt32());  
    leaseDuration = get_readable_address(reply.readInt32());  
  
    info = (ipAddress,gateway,netmask,dns1,dns2,serverAddress,leaseDuration)  
    print "ipAddress %s,\ngateway %s,\nnetmask %s,\ndns1 %s,\ndns2 %s,\nserverAddress %s,\nleaseDuration %s"%info  
    return info  
          
def acquireWifiLock():  
    pass  
def updateWifiLockWorkSource():  
    pass  
def releaseWifiLock():  
    pass  
def initializeMulticastFiltering():  
    pass  
def isMulticastEnabled():  
    pass  
def acquireMulticastLock():  
    pass  
def releaseMulticastLock():  
    pass  
def setWifiApEnabled(wifiConfig,enable):  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    if wifiConfig:  
        _data.writeInt32(1)  
        wifiConfig.writeToParcel(_data)  
    else:  
        _data.writeInt32(0)  
    if enable:  
        _data.writeInt32(1)  
    else:  
        _data.writeInt32(0)  
          
    mRemote.transact(TRANSACTION_setWifiApEnabled, _data,_reply,0)  
    _reply.readExceptionCode()  
  
def getWifiApEnabledState():  
    return transact(TRANSACTION_getWifiApEnabledState)  
  
def getWifiApConfiguration():  
    pass  
def setWifiApConfiguration():  
    pass  
def startWifi():  
    return transact(TRANSACTION_startWifi)  
def stopWifi():  
    return transact(TRANSACTION_stopWifi)  
def addToBlacklist(bssid):  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    if isinstance(bssid,str):  
        bssid = unicode(bssid)  
    _data.writeString16(bssid)  
    mRemote.transact(TRANSACTION_addToBlacklist, _data,_reply,0)  
    _reply.readExceptionCode()  
      
def clearBlacklist():  
    return transact(TRANSACTION_clearBlacklist)  
def getWifiServiceMessenger():  
    pass  
def getWifiStateMachineMessenger():  
    pass  
def getConfigFile():  
    _data = Parcel()  
    _reply = Parcel()  
    _data.writeInterfaceToken(DESCRIPTOR)  
    mRemote.transact(TRANSACTION_getConfigFile, _data,_reply,0)  
    _reply.readExceptionCode()  
    return _reply.readString16()  
  
def captivePortalCheckComplete():  
    return transact(TRANSACTION_captivePortalCheckComplete) != 0

目前并没有实现所有的WifiService的功能,但是像startScan,getScanResults,setWifiEnabled,getWifiEnabledState,getDhcpInfo,setWifiApEnabled这些主要的接口已经实现了,其它接口没有实现并非是因为不能实现,而是比较繁琐,暂时未实现而己,后面会不断的完善。

再来看下测试代码:

test.py

import WifiService  
  
WifiService.setWifiEnabled(True)  
  
WifiService.startScan(True)  
  
print WifiService.pingSupplicant()  
print WifiService.getConfigFile()  
  
for i in range(10):  
    time.sleep(1.0)  
    result = WifiService.getScanResults()  
    if result:  
        print result  
        break

 

执行后将会打印出搜索到的Wifi信息。

另外就是代码的编译问题了。代码必须在android的源代码下进行编译。我试过在ndk上进行编译,经过一番努力,通过链接事先编译好的C++ binder库,也成功编译通过,但是程序不能正常运行,这应该是预先编译出来的库和ndk的库存在兼容性问题造成的,或许通过在ndk上编译binder库可以避免这个问题,但是目前还没有作过尝试。 但是编译出来的代码应该可以运行在各个不同的版本,我在4.0和4.2版本的设备上作了简单的测试,事实证明在4.2上编译的代码可以在4.0上运行,但是考虑到android的诸多版本,各个版本多多少少有些兼容性问题,更详细的还必须比较各个版本的binder代码,并通过测试才能得到结果。


当前题目:如何从python代码中直接访问Android的Service
当前网址:http://scyanting.com/article/pgdepo.html