作者:台艾辉_435 | 来源:互联网 | 2023-09-23 21:43
前言 在实际开发中不同语言不同平台使用的加载使用的JNI包是不同的,在android平台中生成的多渠道*.so包并不能在直接Linux平台上使用。并且在windows上需要使
前言
在实际开发中不同语言不同平台使用的加载使用的JNI包是不同的,在android平台中生成的多渠道*.so包并不能在直接Linux平台上使用。并且在windows上需要使用dll。现在就有这样一个场景,一个算法so包需要在Android端使用,也需要在后端使用,后端服务器不定,可能是Linux也可能是winServer。
目录
前言
Android-so
Linux-so (可复用时,不可复用时 JDK准备,GCC/G++)
1、可复用环境时
2、不可复用时
Windows-dll
Android-so
有很多博客关于android-so如何进行打包,早期的jni方式原文链接,还有就是在建立Android项目时默认支持C++,项目创建后目录会自动生成cpp文件夹,这种方式默认使用Cmake,可以很好地进行混合编译其他so包。
关于android studio3.3升级后没有include c++ support,在创建项目时,select a Project Template滑到最后就可以找到Native C++,这正是我们需要创建的项目。
创建流程完毕后,我们将在项目中看cpp文件以及已经生成好的模板代码。
可以自行对模板代码进行编辑,然后执行gradle中的 externalNativeBuildRelease 命令
生成的so包将在app下图所示的目录中找到
这样的方法比较方便与快捷。
Linux-so (可复用时,不可复用时 JDK准备,GCC/G++)1、可复用环境时
在linux环境下打包主要依赖当前环境下的JDK环境,gcc、g++,如果可以复用java类JNI头文件,则只需要加入jni_md.h、jni.h这两个头文件即可
如下环境:CentOS7.4 /AMD64
jni.h所在目录:usr/java/${your_jdk_version_folder}/include/jni.h
jni_md.h所在目录:usr/java/${your_jdk_version_folder}/include/linux/jni_md.h
此时,新建一个目录中,包含
- ${java类头文件}.h
- jni.h
- jni_md.h
- ${c源码文件}.c/${c++源码文件}.cpp
此时在此目录打开终端,执行
c语言:gcc *.c -fPIC -shared -o libname.so
c++语言:g++ *.cpp -fPIC -shared -o libname.so
2、不可复用时
2.1检查JDK是否安装,终端输入java -version
2.2gcc/g++,注意检查版本号,源代码使用C语言对应使用gcc,源代码使用C++语言对应使用g++;
[juan@juan~]$ gcc --version
gcc (GCC) 4.6 . 3 20120306 (Red Hat 4.6 . 3 - 2 )
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[qiaoning@qiaoning ~]$ g++ --version
bash: g++: command not found...
[qiaoning@qiaoning ~]$ gcc --version
gcc (GCC) 4.6 . 3 20120306 (Red Hat 4.6 . 3 - 2 )
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2.3关于头文件及源码的处理
建议使用android文件中生成的头文件与源码 ,若只需要在linux环境下进行打包操作,则可以进行下面的操作:
2.3.1建立Java类:
public class JNITest{
static {
try {
System.loadLibrary("JNITest" );
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
}
}
public native int add(int value1, int value2);
}
在终端输入 javac JNITest.java 后生成JNITest.class 文件
然后:javah Hello 生成 Hello.h文件
2.3.1 在相同的目录下建立JNITest.cpp:
#include "JNITest.h"
#include
// 与 Hello.h 中函数声明相同
JNIEXPORT void JNICALL Java_Hello_SayHello (JNIEnv * env, jobject arg, jint value1,jint value2)
{
return value1+value2;
}
此时进入 1可复用环境步骤,在上面。
2.4 最后是java测试代码:
public class ADDTest
{
public static void main(String argv[])
{
JNITest test = new JNITest();
int result = test.add(90,90);
System.out.print("JNITest result:" + result);
}
}
测试成功会打印:“JNITest result:180”
2.5 注意事项:
1 . 如果可以通过 TCP/IP 实现 Java 代码与本地 C/C++ 代码的交互工作,那么最好不使用以上提到的 JNI 的方式,因为一次 JNI 调用非常耗时,大概要花 0.5 ~ 1 个毫秒。
2 . 在一个 Applet 应用中,不要使用 JNI。因为在 applet 中可能引发安全异常。
3 . 将所有本地方法都封装在单个类中,这个类调用单个 DLL。对于每种目标操作系统,都可以用特定于适当平台的版本替换这个 DLL。这样就可以将本地代码的影响减至最小,并有助于将以后所需的移植问题包含在内。
4 . 本地方法要简单。尽量将生成的 DLL 对任何第三方运行时 DLL 的依赖减到最小。使本地方法尽量独立,以将加载 DLL 和应用程序所需的开销减到最小。如果必须要运行时 DLL,则应随应用程序一起提供它们。
5 . 本地代码运行时,没有有效地防数组越界错误、错误指针引用带来的间接错误等。所以必须保证保证本地代码的稳定性,因为,丝毫的错误都可能导致 Java 虚拟机崩溃。
Windows-dll
在window环境需要使用到jni需要将源码打包成dll是形式,其工具可以参考GCC打包dll文件-MinGW-w64 C/C++编译器,其步骤与Linux是一致的。