开发环境为windows下wsl ubuntu22.04, java版本(原本打算用powershell纯windows环境弄,但不知道为什么-Djava.library.path
一直指定不了报Linkerror,算了):
java -version
openjdk version "1.8.0_412"
OpenJDK Runtime Environment (build 1.8.0_412-8u412-ga-1~22.04.1-b08)
OpenJDK 64-Bit Server VM (build 25.412-b08, mixed mode)
首先建立一个教程项目做一个示例,用普通的文本编辑器就行(我是用vscode),不需要IDE高级功能:
一个简单的案例1
最后生成的项目目录应该如下:
ll
\total 16
drwxrwxrwx 1 root root 512 Jul 9 10:13 ./
drwxrwxrwx 1 root root 512 Jul 9 09:01 ../
-rwxrwxrwx 1 root root 243 Jul 9 09:39 MyLog.c*
-rwxrwxrwx 1 root root 467 Jul 9 10:13 MyLog.class*
-rwxrwxrwx 1 root root 387 Jul 9 10:13 MyLog.h*
-rwxrwxrwx 1 root root 285 Jul 9 09:01 MyLog.java*
-rwxrwxrwx 1 root root 15584 Jul 9 10:12 libclog.so*
编写MyLog.java和MyLog.c:
MyLog.java
public class MyLog {
//获取c代码的日志
native void outputLog(String str);
static { System.loadLibrary("clog");}
public static void main(String[] args) {
MyLog a = new MyLog();
a.outputLog("I from Java!!!");
}
}
一个指令生成MyLog.java的class并生成MyLog.h:
javac MyLog.java -h .
MyLog.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MyLog */
#ifndef _Included_MyLog
#define _Included_MyLog
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: MyLog
* Method: outputLog
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_MyLog_outputLog
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
为MyLog.h编写MyLog.c:
MyLog.c
```c
#include "MyLog.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_MyLog_outputLog
(JNIEnv *env, jobject obj,jstring str)
{
const char *cStr = (*env)->GetStringUTFChars(env, str, 0);
printf("%s!\n", cStr);
return;
}
```
编译so库:
gcc -shared -o libclog.so MyLog.c -I/usr/lib/jvm/java-8-openjdk-amd64/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/
终于可以运行java了,但并不能直接运行,因为java找不到so库的路径:
java -cp ./java HelloWorld
Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path:
可以用-Djava.library.path
指定库路径:
java -Djava.library.path=. MyLog
如果成功应打印I from Java!!!!
一个简单的案例2
尝试将文件组织化,分c和java,再试一次:
root@WINDOWS-1FNAO0N:/mnt/d/CodeDraft/android_ndk_test/case1_hello# tree
.
├── c
│ ├── HelloWorld.c
│ ├── HelloWorld.h
│ ├── android.mk
│ └── application.mk
└── java
├── HelloWorld.class
└── HelloWorld.java
- java目录建立
HelloWorld.java
如下:
class HelloWorld
{
public static native void displayHelloWorld();
{
System.loadLibrary("hello");
}
public static void main(String[] args)
{
new HelloWorld().displayHelloWorld();
}
}
- 用javac生成
HelloWorld.class
和HelloWorld.h
javac java/HelloWorld.java -h ./c
note: 也可以用javah
生成HelloWorld.java
:
javah HelloWorld
但是该工具在jdk10时被弃用,原因是javac能够达到同样的功能,因此这里兼容起见用javac
-
编译HelloWorld.c的生成动态链接库,上个参考例子是用gcc的,这次用安卓ndk使用的
mk
文件,类似于makefile,ndk本质是对clang的封装。记得include jni.h 和 jni_md.h的路径,android是用
LOCAL_C_INCLUDES
这个宏,而gcc则用-I
指定。我这里jni.h和jni_md.h的路径如下,读者可根据自己jdk的安装路径自行修改:
/usr/lib/jvm/java-8-openjdk-amd64/include/jni.h /usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h
编写android.mk如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libhello LOCAL_SRC_FILES := HelloWorld.c LOCAL_C_FLAGS := -fPIC -g -Wall include $(BUILD_SHARED_LIBRARY)
各种参数可参考:ndk-build官方使用说明
在application.mk中可指定安卓平台api版本,abi架构,android.mk位置:
application.mk
APP_PLATFORM=android-33 APP_ABI=armeabi-v7a x86 APP_BUILD_SCRIPT=./c/android.mk
编译:
root@WINDOWS-1FNAO0N:/mnt/d/CodeDraft/android_ndk_test/case1_hello#
ndk-build NDK_PROJECT_PATH=./ NDK_APPLICATION_MK=./c/application.mk
附带一个gcc示例:
gcc -shared ./c/HelloWorld.c -o libhello.so -I/usr/lib/jvm/java-8-openjdk-amd64/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/
android.mk生成的libhello.so库可在c/libs
看到
tree
.
├── c
│ ├── HelloWorld.c
│ ├── HelloWorld.h
│ ├── android.mk
│ ├── application.mk
│ ├── libs
│ │ ├── armeabi-v7a
│ │ │ └── libhello.so
│ │ ├── x86
│ │ │ └── libhello.so
在命令行用-D
参数指定
root@WINDOWS-1FNAO0N:/mnt/d/CodeDraft/android_ndk_test/case1_hello#
java -Djava.library.path=./c/libs/armeabi-v7a -cp ./java HelloWorld
如果正常输出,结果应该如下:
Hello world!
参考:
NDK相关:
csdn:使用NDK编译C/C++文件生成在安卓中的可执行文件
腾讯云:(NDK编译)详解使用Android.mk编译的C/C++程序过程
https://developer.android.com/ndk/guides/android_mk?hl=zh-cn
JNI相关: