Android 平台的Python——CLE方案实现(三)

Android 平台的Python——基础篇(一)
Android 平台的Python——JNI方案(二)
Android 平台的Python——CLE方案实现(三)
Android 平台的Python——第三方库移植
Android 平台的Python——编译Python解释器

更新:本文已过时!!!CLE不再被推荐,接口不友好,且未提供一些需要编译的Python 第三方库,如numpy、pillow等等,推荐更新的方案 Android与Python混合编程

CLE(Common Language Extension)公共语言拓展
官网:http://www.srplab.com/cn/index.html
来自官网的简介:
CLE中间件支持多脚本语言混合编程。c/c++, lua, python, c#, ruby, java等语言可以通过CLE中间件直接使用其它语言中的类,函数,变量或者模块, 使得现有的功能库或者模块可以很容易的应用到其它编程语言中。开发者可以使用熟悉的语言编写功能库,然后在其它语言开发的应用中使用。CLE非常简单,其执行体仅为一个核心共享库和对应于每个脚本语言接口的共享库.

我们建议开发人员使用脚本语言编写主逻辑,并使用平台相关的语言开发GUI或设备特定部分。这样不仅可以保证应用程序的可移植性,而且还利用了平台SDK的优势。使用脚本语言可能会导致安装包的大小增加, 性能略有下降,但随着硬件性能提高和存储增加, 这些将不成为问题

在Android中通过CLE框架,实现与Python交互(以下内容为eclipse环境)

注:本博客之前以eclipse环境为主,后续有读者反馈,Android Studio下无法运行,在Android Studio下

  1. libs目录中请不要导入android-support-v4.jar
  2. 请在工程app目录下的build.gradle中对jni进行配置
android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "org.study"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }

    // jni配置
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

1、环境准备

在官网下载最新的CLE for Android 开发包,其中包含示例工程和API文档。解压开发包,拷贝如下文件

  • 拷贝 starcore_android_rX.X.jar到工程的libs目录
  • 拷贝 libstar_java.so、libstarcore.so、libpython3.4m.so和libstar_python34.so到libs目录

Android 平台的Python——CLE方案实现(三)_第1张图片

2、编写Python代码

text.py

def add(x,y) :
    return x+y

calljava.py

import imp  #test load path

def log(content):
    JavaClass.d("formPython",content)

log("Hello Android,form python")

py_code.py

import time

def get_time():
    return time.time()

将py_code.py压缩为py_code.zip文件。将编写的Python源码放入Android 工程的assets目录,其中还要包含一些Python需要的环境及标准库,见下图

Android 平台的Python——CLE方案实现(三)_第2张图片

3、编写Android相关代码,初始化CLE并调用Python

public class MainActivity extends Activity {

	public StarSrvGroupClass SrvGroup;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final File appFile = getFilesDir();  /*-- /data/data/packageName/files --*/
		final String appLib = getApplicationInfo().nativeLibraryDir;

		AsyncTask.execute(new Runnable() {
			
			@Override
			public void run() {
				loadPy(appFile,appLib);
			}
		});
	}

	void loadPy(File appFile,String appLib){
		//拷贝Python相关环境
		File pythonLibFile = new File(appFile, "python3.4.zip");
		if (!pythonLibFile.exists()) {
			copyFile(this, "python3.4.zip");
			copyFile(this, "_struct.cpython-34m.so");
			copyFile(this, "binascii.cpython-34m.so");
			copyFile(this, "time.cpython-34m.so");
			copyFile(this, "zlib.cpython-34m.so");
		}

		// 拷贝Python 代码
		copyFile(this, "calljava.py");
		copyFile(this, "test.py");

		try {
			// 加载Python解释器
			System.load(appLib + File.separator + "libpython3.4m.so");
			
			// 除了将代码直接拷贝,还支持将代码压缩为zip包,通过Install方法解压到指定路径
			InputStream dataSource = getAssets().open("py_code.zip");
			StarCoreFactoryPath.Install(dataSource, appFile.getPath(),true );
		} catch (Exception e) {
			e.printStackTrace();
		}

		/*----init starcore----*/
		StarCoreFactoryPath.StarCoreCoreLibraryPath = appLib;
		StarCoreFactoryPath.StarCoreShareLibraryPath = appLib;
		StarCoreFactoryPath.StarCoreOperationPath = appFile.getPath();

		StarCoreFactory starcore = StarCoreFactory.GetFactory();
		StarServiceClass Service = starcore._InitSimple("test", "123", 0, 0);
		SrvGroup = (StarSrvGroupClass) Service._Get("_ServiceGroup");
		Service._CheckPassword(false);

		/*----run python code----*/
		SrvGroup._InitRaw("python34", Service);
		StarObjectClass python = Service._ImportRawContext("python", "", false, "");
		// 设置Python模块加载路径
		python._Call("import", "sys");
		StarObjectClass pythonSys = python._GetObject("sys");
		StarObjectClass pythonPath = (StarObjectClass) pythonSys._Get("path");
		pythonPath._Call("insert", 0, appFile.getPath()+ File.separator +"python3.4.zip");
		pythonPath._Call("insert", 0, appLib);
		pythonPath._Call("insert", 0, appFile.getPath());

        //调用Python代码
		Service._DoFile("python", appFile.getPath() + "/py_code.py", "");
		long time = python._Calllong("get_time");
		Log.d("", "form python time="+time);
		
		Service._DoFile("python", appFile.getPath() + "/test.py", "");
		int result = python._Callint("add", 5, 2);
		Log.d("", "result="+result);
		
		python._Set("JavaClass", Log.class);
		Service._DoFile("python", appFile.getPath() + "/calljava.py", "");
	}
	
	private void copyFile(Context c, String Name) {
		File outfile = new File(c.getFilesDir(), Name);
		BufferedOutputStream outStream = null;
		BufferedInputStream inStream = null;

		try {
			outStream = new BufferedOutputStream(new FileOutputStream(outfile));
			inStream = new BufferedInputStream(c.getAssets().open(Name));

			byte[] buffer = new byte[1024 * 10];
			int readLen = 0;
			while ((readLen = inStream.read(buffer)) != -1) {
				outStream.write(buffer, 0, readLen);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (inStream != null) inStream.close();
				if (outStream != null) outStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

以上代码即完成了Java与Python的互相调用,其中python._Set("JavaClass", Log.class)一句,指将一个java类设置给Python,变成Python类,第一个参数指定在Python中的类名,此处随意起了一个类名JavaClass,该类可直接在Python中使用,如上将Android的日志输出类设置给Python使用

关于CLE的相关原理,可进入官网了解,更多详细用法,见CLE文档

关注个人公众号:编程之路从0到1

编程之路从0到1

你可能感兴趣的:(Python3新天地,Android技术,python3,android,so,CLE)