之前我写过一篇博客,java代码从初始化到具象执行,里面介绍了如何初始化在命令行下调用java虚拟机执行java代码的方法。最近有个需求,要在android手机上用命令行执行java代码。 需求是可行的,因为很多adb shell 中的指令,比如am、sm 都是java的代码写的,他们保存成jar文件,通过 sh 去调它。

查了一下资料,摸索了dalvikvm加载so库的方法,把方法整理成文章给自己做个笔记吧~

本地编译运行 java

写一个java 文件,编译成class,在本机器上执行一下看看效果 -> 参考java代码从初始化到具象执行

vim Test.java

public final class Test{
        public static final String  s1 = "hello Yeshen!";
        public static void main(String[] args){
                System.out.println(s1);
        }
}
javac Test.java
java Test

本地编译运行 java 带原生代码(ubuntu)

vim HelloJNI.java

public class HelloJNI{
    static {
        System.loadLibrary("hello");
    }

    private native String stringFromJNI();

    private native String stringToJNI(String string);

    public static void main(String[] args){
        if (args == null || args.length == 0) {
            System.out.print(new HelloJNI().stringFromJNI());
        } else {
            StringBuilder echo = new StringBuilder();
            for (String s : args) {
                echo.append(s);
            }
            System.out.print(new HelloJNI().stringToJNI(echo.toString()));
        }
    }
}

javac -h . HelloJNI.java
cat HelloJNI.h
vim HelloJNI.c

#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"

JNIEXPORT jstring JNICALL Java_HelloJNI_stringFromJNI
  (JNIEnv *env, jobject thisobj){
    const char* hello = "Hello from C++";
    return (*env)->NewStringUTF(env,hello);
}

JNIEXPORT jstring JNICALL Java_HelloJNI_stringToJNI
  (JNIEnv *env, jobject thisobj, jstring from){
    const char* hello = "echo:";
    return (*env)->NewStringUTF(env,hello);
}
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
gcc -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -shared -o libhello.so HelloJNI.c
java -Djava.library.path=. HelloJNI

Android上运行 java

把 class 处理成 dalvikvm 能使用的 jar

这里需要有android build-tool 的工具集。如果你是android开发的话,找一下本机的

~/Library/Android/sdk/build-tools/28.0.3/dx

cd ~/Library/Android/sdk/build-tools/28.0.3/
PATH=$PATH:$(pwd)
cd -

jar -cvf Test.jar Test.class
dx --dex --output=classes.dex Test.jar 
aapt add run.jar classes.dex

adb push run.jar /sdcard/Download/
adb shell dalvikvm -classpath /sdcard/Download/run.jar Test

到这一步,纯粹的java代码就已经可以运行了 :)

Android 上运行 java 带原生代码

java 中使用 native(c/c++) 的方法。方法和上面的类似,就跳过了,但是有两个注意点:

1,选择制定平台的gcc编译器

但是编译so的时候要注意,不能直接用本机的gcc,要用指定平台的gcc

~/Android/Sdk/ndk-bundle/toolschains

我的手机是 armeabi-v7a mumu模拟器上则是 x86

2, java.library.path 不能在sdcard上,sdcard可拆卸,要放在不可拆卸的目录,比如 /data/local/tmp

(PS:这里可能会要求有root权限来读写磁盘)

具体命令行脚本如下:

adb push libhello.so /data/local/tmp
adb shell dalvikvm -Djava.library.path=/data/local/tmp \
-classpath /sdcard/Download/run.jar Test

相关代码已开源

https://github.com/wuyisheng/simple-java

参考文章:

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐