最近在公司做一個項目,想把之前Linux小組做了三四年的一個項目移植到Android平臺上玲躯。如果讓Android從頭開始做据德,估計又是三四年時間去對接不同平臺鳄乏,而且還需要兩個組同時維護跷车,這樣太不劃算了。所以就打算把Linux上的程序移植到Android上橱野,Android只需要提供一些特有的接口給C就好了朽缴,以后只維護一套代碼,簡單方便水援。
經過一天的嘗試密强,最終成功完成了一個滿足需求的Demo,整體結構如下:
整體來看也比較簡單蜗元,Java調JNI或渤,JNI啟動Linux程序,Linux程序運行中需要操作界面時再用JNI的反射方法調用到Java層修改界面奕扣。
接下來看下具體實現:
代碼結構
LinuxHandler.java 定義native方法和等待反射調用方法
Androidhandle.c Linux代碼調用方法反射Java層
demo.c Linux小組同事提供的測試代碼薪鹦,里面有他們簡化的業(yè)務邏輯
linuxhandle.c JNI方法
LinuxHandler.java
Java層啟動
public class LinuxHandle {
public native void startLinux();
public void speak(String msg) {
Log.e("TEST", "speak C-> " + msg);
}
public void showMsg(String msg) {
Log.e("TEST", "showMsg C-> " + msg);
}
}
定義了三個方法,native方法startLinux()從Java層啟動Linux程序,另外兩個是模擬等待反射調用的操作界面方法池磁。
linuxhandle.c
真正去啟動Linux程序
#include <jni.h>
#include "linuxhandle.h"
#include "demo.h" //Linux C 頭文件奔害,調用main()方法
JavaVM *local_jvm = NULL;
jobject local_object = NULL;
/*
* Class: com_***_linuxdemo_LinuxHandle
* Method: startLinux
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_***_linuxdemo_LinuxHandle_startLinux
(JNIEnv *env, jobject object) {
(*env)->GetJavaVM(env, &local_jvm); //保存到全局變量JVM中
local_object = (*env)->NewGlobalRef(env, object); /* 創(chuàng)建對象的本地變量 */
main(); //啟動Linux C程序
}
Androidhandle.c
等待Linux程序調用
#include <jni.h>
#include "linuxhandle.h"
void showMessage_c(char *message) {
extern JavaVM *local_jvm; //獲取全局JVM,由它獲取JNIEnv
JNIEnv *env = NULL;
extern jobject local_object;
(*local_jvm)->AttachCurrentThread(local_jvm, &env, NULL);
jclass jclass1 = (*env)->FindClass(env, "com/***/linuxdemo/LinuxHandle");
jmethodID methodID = (*env)->GetMethodID(env, jclass1, "showMsg",
"(Ljava/lang/String;)V");
(*env)->CallVoidMethod(env, local_object, methodID, (*env)->NewStringUTF(env, message));
}
void speak_c(char *text) {
LOGE("speak at C");
//同樣反射到Java層
}
Demo.c
#include "Androidhandle.h"
int main(void) {
speak_c("1234");
...... //公司業(yè)務邏輯代碼
showMessage_c("adc");
}
我自己做完后也做了多次驗證地熄,并且導入第三方SO庫測試也沒有問題华临,但因為還只是個驗證可行性的Demo,后面就要開始正式做移植的項目了端考,如果遇到了什么坑我會盡快補上雅潭。