我使用的是虚拟android设备,故对应的CLE中库文件版本为/x86,你可以根据自己开发环境找到对应的版本。调用的python版本为3.7,以下为主要步骤:
1、环境准备
在官网下载最新的CLE for Android 开发包,其中包含示例工程和API文档。
解压开发包,拷贝如下文件
- 拷贝 starcore_android_rX.X.jar到工程的libs目录。(该jar文件在download的starcore_for_android.3.2.0中)
- 拷贝libstar_java.so、libstarcore.so、libpython3.7m.so和libstar_python37.so到libs/x86目录。(除了libpython3.7m.so在android.python.3.7.0下载文件中,其余都在download的starcore_for_android.3.2.0/libs/x86中)
2、编写Python代码
/----test.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.3.7.0下载文件/x86目录下)
如果没有发现assets目录,则如下选择Android下添加:
3、编写Android相关代码,初始化CLE并调用Python
首先需要修改build.gradle文件:
添加jni库文件路径:
// jni配置
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
然后编写Android相关代码,初始化CLE并调用Python
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.os.AsyncTask;
import android.app.Activity;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;
import com.srplab.www.starcore.*;
public class MainActivity extends AppCompatActivity {
public StarSrvGroupClass SrvGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
final File appFile = getFilesDir(); /*-- /data/data/packageName/files --*/
final String appLib = getApplicationInfo().nativeLibraryDir;
loadPy(appFile,appLib);
// AsyncTask.execute(new Runnable() {
//
// @Override
// public void run() {
// loadPy(appFile,appLib);
// }
// });
}
void loadPy(File appFile,String appLib){
//拷贝Python相关环境
File pythonLibFile = new File(appFile, "python3.7.zip");
if (!pythonLibFile.exists()) {
copyFile(this, "python3.7.zip");
copyFile(this, "_struct.cpython-37m.so");
copyFile(this, "binascii.cpython-37m.so");
copyFile(this, "time.cpython-37m.so");
copyFile(this, "zlib.cpython-37m.so");
}
// 拷贝Python 代码
copyFile(this, "calljava.py");
copyFile(this, "test.py");
try {
// 加载Python解释器
System.load(appLib + File.separator + "libpython3.7m.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("python37", Service); // this place
StarObjectClass python = Service._ImportRawContext("python", "", false, "");
/*调用tensorflow*/
//个人推荐使用这种写法,看起来比较直观,不容易带给自己误解
python._Call("eval", "import sys");
// python._Call("eval", "sys.path.append(r'" + path + "')");
python._Call("eval", "import numpy as np");
python._Call("eval", "import pred as pd");
//这里在导入tensorflow模型后获得模块接口,可以使用model._Call("func")
//相当于python._Call("eval", "pd.func()"),但是前一种方法没法保存返回结果
StarObjectClass model = python._GetObject("pd");
python._Call("eval", "import operate_data as processor");
// processor = python._GetObject("processor");
// 设置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.7.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(Activity 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();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
以上是我新建了一个basic activity工程,里面的MainActivity.java文件中初始化python模块并调用文件和函数代码。
代码中python._Set(“JavaClass”, Log.class)一句,指将一个java类设置给Python,变成Python类,第一个参数指定在Python中的类名,此处随意起了一个类名JavaClass,该类可直接在Python中使用,如上将Android的日志输出类设置给Python使用,完成了Java与Python的互相调用。具体tensorflow模型的使用还只是初尝,等我全部走完美了再来补充。