在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。

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<:iservicemanager> 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<:iservicemanager> sm = android::defaultServiceManager();

Vector list = sm->listServices();

for (int i=0;i

{

visitor(list[i].string(),list[i].size(),data);

}

return list.size();

}

int binder_getInterfaceDescriptor(void *binder,char16_t *descriptor,size_t size)

{

sp *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的底层实现也正是对这两个类进行封装的结果,具体的可以看

frameworksbasecorejniandroid_util_Binder.cpp

的代码,

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

binder.pyxcdef 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.pyfrom 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.pyimport 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代码,并通过测试才能得到结果。

mpython 直接访问_如何从python代码中直接访问Android的Service相关推荐

  1. python from import找不到库_如何查找python代码中所有未使用到的from与import的类库...

    假定你的代码中都没有直接从locals()/globals()中获取b的引用,那这还是比较容易的,下面给你举个例子吧. 比如这段代码:from a import b b 你可以用python的comp ...

  2. python嵌入c代码_怎样把Python代码嵌入到C程序

    匿名用户 1级 2017-11-03 回答 这篇文章主要介绍了将Python代码嵌入C++程序进行编写的实例,尽管通常还是Python代码中调用C++程序的情况较多...需要的朋友可以参考下 把pyt ...

  3. Python代码中的三大常见“愚形”,你中招了吗?

    愚形,是围棋的专业术语,凡是效率低下且不美观的棋形,统称为愚形.比如空三角和团子,就是典型的愚形.低水平棋手经常会在无意中走出愚形,而那些高手平棋手,尽管在生死存亡的危机时刻也会用愚形求生或者逃命,但 ...

  4. pythonproperty装饰器_实例讲解Python编程中@property装饰器的用法

    取值和赋值 class Actress(): def __init__(self): self.name = 'TianXin' self.age = 5 类Actress中有两个成员变量name和a ...

  5. python代码中添加环境变量

    比如命令行需要: export MASTER_PORT=5678 在python代码中就是: import osos.environ['MASTER_PORT'] = '5678'

  6. python另存为excel_为什么不能从python代码中“另存为”Excel文件?

    我有一条蟒蛇 ExcelDocument 类,它为读取/写入/格式化Excel文件提供了基本的方便方法,而我在看似简单的Python代码中遇到了一个奇怪的错误.我有一个储蓄和 saveAs 方法: d ...

  7. 在python代码中调用vba宏的四种方法

    在python代码中调用vba宏 工作以python为主体,但是遇到了一些word操作的需求(详见上一篇),这个需求用word自带的功能会很容易实现,于是就想着能不能用python调用宏来处理. 网上 ...

  8. Python代码中的数学之美:从自由落体到爬虫悖论,十分钟开启数学思维

    数学思维,就是用数学的方式去解决问题,就象吃饭用筷子.喝水用杯子一样,自然而然又理所当然.数学思维并非知识的积累,而是一种由特定思维习惯蕴育而成的能力--这种特定习惯的养成,往往是从解决看似简单的问题 ...

  9. python代码中疯狂print影响python性能吗?print是io吗?结论是做代码性能测试千万不要疯狂print,否则结果严重不准确,性能大幅下降。...

    很多人做性能测试,吧print打开,吧log调到debug级别并使用了streamhandler,那就会疯狂打印到控制台. 打印控制台会影响代码性能吗?这是毫无疑问的,python print会严重影 ...

最新文章

  1. C++添加程序到windows的启动项的代码
  2. python怎么输出浮点数_python 零基础入门教程第 2 章:基本数据类型 (一)
  3. JavaScript History对象
  4. nginx假死导致的问题回顾
  5. WSGI接口(廖雪峰重点)
  6. javascript中的异步编程
  7. 怎样去理解@ComponentScan注解
  8. PyTorch框架学习十三——优化器
  9. Socket编程模式理解与对比
  10. java自学之路-day19
  11. EasyUI DataGrid 添加排序
  12. 个人计算机网刻系统,诚龙网维全自动pxe网刻工具_win7网刻工具_网刻win7系统工具...
  13. 获取ipa文件下载链接(appstore下载链接)
  14. 一起谈.NET技术,走向ASP.NET架构设计——第二章:设计/ 测试/代码
  15. Electron 使用 regedit 控制注册表(实现win文件右键菜单)
  16. LaTeX中的参考文献BibLaTeX
  17. 教师节快乐:带大家回顾这十位大师笔下的教师!
  18. 【学习笔记】产品经理必备技能之竞品分析(下)用户体验五要素分析法 + 竞品分析报告
  19. 科大讯飞AI营销大赛 CTR预估总结
  20. 2018CVPR_Future Frame Prediction for Anomaly Detection – A New Baseline

热门文章

  1. java中位数_java 计算中位数方法
  2. 乐观锁和悲观锁_什么是悲观锁和乐观锁?
  3. python为什么没有指针_Python 没有指针,如何解算法题?
  4. PyTorch框架学习一——PyTorch的安装(CPU版本)
  5. 基于 frida 实现的逆向工具包 hooker
  6. 菜鸟教程 之 JavaScript 函数(function)
  7. Linux 输入输出重定向 2>/dev/null和>/dev/null 2>1和2>1>/dev/nul
  8. csplit 分割文件
  9. Python编程从入门到实践~函数
  10. 性能测量工具类——TimeMeasureUtil TimeMeasureProxy