pybridge编译
2019-08-10 本文已影响0人
HAPPYers
通过JNI实现和python的运行交互
项目地址
编译运行
下载crystax ndk
https://www.crystax.net/
为了在Linux平台编译,此处下载的是crystax-ndk-10.3.2-linux-x86_64.tar.xz,如果要在Windows平台上编译,则下载crystax-ndk-10.3.2-windows-x86.exe即可。
生成so文件
切换到main/jni
目录下面。
- 首先要修改一下
Application.mk
文件,选取自己需要的平台APP_ABI
APP_PLATFORM := android-19
APP_ABI := armeabi arm64-v8a x86 x86_64 armeabi-v7a mips mips64
生成各平台so文件的时候如果报类似app/src/main/obj/local/armeabi-v7a/objs/pybridge/pybridge.o.d:1: *** target pattern contains no %'. Stop.
的错误,将src/main
文件夹下的obj
文件夹删除,再次生成即可。
- 在
jni
目录下运行path/to/crystax/ndk-build
最后生成结果:文件都生成在src/main/libs
的各平台文件夹下面,取所需要的平台即可。
happy@ubuntu ~/Source/pybridge/app/src/main/jni /home/happy/Source/crystax-ndk-10.3.2/ndk-build
[armeabi] Compile thumb : pybridge <= pybridge.c
[armeabi] SharedLibrary : libpybridge.so
[armeabi] Install : libcrystax.so => libs/armeabi/libcrystax.so
[armeabi] Install : libpybridge.so => libs/armeabi/libpybridge.so
[armeabi] Install : libpython3.5m.so => libs/armeabi/libpython3.5m.so
[arm64-v8a] Compile : pybridge <= pybridge.c
[arm64-v8a] SharedLibrary : libpybridge.so
[arm64-v8a] Install : libcrystax.so => libs/arm64-v8a/libcrystax.so
......
[mips64] SharedLibrary : libpybridge.so
[mips64] Prebuilt : libgnustl_shared.so <= <NDK>/sources/cxx-stl/gnu-libstdc++/5/libs/mips64/
[mips64] Install : libcrystax.so => libs/mips64/libcrystax.so
[mips64] Install : libpybridge.so => libs/mips64/libpybridge.so
[mips64] Install : libpython3.5m.so => libs/mips64/libpython3.5m.so
运行
在Android studio中构建项目运行即可。
魔改
代码功能
-
AssetExtractor.java
将APK的assets文件夹下的python文件拷贝到内部存储。很好的工具类,代码见此AssetExtractor -
PyBridge.java
控制与python解释器的交互 -
pybridge.c
实现JNI C接口并处理CPython API -
bootstrap.py
Python解释器初始化时运行的脚本
assets文件夹下的
call python函数的实现
/**
This function is responsible for receiving a payload string
and sending it to the router function defined in the bootstrap.py
file.
*/
JNIEXPORT jstring JNICALL Java_com_jventura_pybridge_PyBridge_call
(JNIEnv *env, jclass jc, jstring payload)
{
LOG("Call into Python interpreter");
// Get the payload string
jboolean iscopy;
const char *payload_utf = (*env)->GetStringUTFChars(env, payload, &iscopy);
// Import module
PyObject* myModuleString = PyUnicode_FromString((char*)"bootstrap");
PyObject* myModule = PyImport_Import(myModuleString);
// Get reference to the router function
PyObject* myFunction = PyObject_GetAttrString(myModule, (char*)"router");
PyObject* args = PyTuple_Pack(1, PyUnicode_FromString(payload_utf));
// Call function and get the resulting string
PyObject* myResult = PyObject_CallObject(myFunction, args);
char *myResultChar = PyUnicode_AsUTF8(myResult);
// Store the result on a java.lang.String object
jstring result = (*env)->NewStringUTF(env, myResultChar);
// Cleanup
(*env)->ReleaseStringUTFChars(env, payload, payload_utf);
Py_DECREF(myModuleString);
Py_DECREF(myModule);
Py_DECREF(myFunction);
Py_DECREF(args);
Py_DECREF(myResult);
return result;
}