admin 管理员组文章数量: 887186
1、so文件介绍
“so”文件是使用C/C++编写生成的,在Android 平台上快速编译、打包该文件,它是一个动态链接库,而生成“so”文件其实就是JNI开发。
2、JNI开发简介
(1)、JNI简介
JNI全称为Java Native Interface(JAVA本地调用)。从Java1.1开始,JNI成为java平台的一部分,它允许Java代码和其他语言写的代码(如C&C++)进行交互。并非从Android发布才引入JNI的概念的。
JNI是一个协议,这个协议用来沟通java代码和外部的本地代码(c/c++),外部的c/c++代码也可以调用java代码。
(2)、JNI的作用
- 效率上 C/C++是本地语言,比java更高效;
- 代码移植,如果之前用C语言开发过模块,可以复用已经存在的c代码;
- java反编译比C语言容易,一般加密算法都是用C语言编写,不容易被反编译。
(3)、JNI的数据类型
Java的数据类型是跟C/C++的数据类型是不一样的,而JNI是处于Java和Native本地库(大部分是用C/C++写的)中间的一层,JNI对于两种不同的数据类型之间必须做一种转换,所以在JNI跟Java之间就会有数据类型的对应关系。
JNI的数据类型包含两种:基本类型和引用类型。基本类型主要有jboolea、jchar、jbyte等,他们和Java中的数据类型的对应关系如下图所示:
JNI中的引用类型主要有类、对象和数组,他们和Java中的引用类型的对应关系如下图所示:
(4)、JNI函数命名规则
javah生成的c/c++头文件的时候,会对java中定义的 native 函数生成对应的jni层函数,如下:
#include <cn_xinxing_jnitest_CalculateUtils.h>
JNIEXPORT jstring JNICALL Java_cn_xinxing_jnitest_CalculateUtils_getStringFromNative
(JNIEnv * env, jobject obj, jstring str){
return str;
}
首先函数名的格式遵循如下规则:Java_包名_类名_方法名。比如
Java_cn_xinxing_jnitest_CalculateUtils_getStringFromNative (JNIEnv * env, jobject obj, jstring str)
其中cn_xinxing_jnitest是包名,CalculateUtils是类名,getStringFromNative是方法名,jstring 是方法的String类型的参数。JNIEXPORT、JNICALL、JNIEnv和jobject都是JNI标准中所定义的类型或者宏,它们的含义如下:
-
JNIEnv * :表示一个指向JNI环境的指针,可以通过它来访问JNI提供的接口方法;
-
jobject: 表示Java对象种的this;
-
JNIEXPORT和JNICALL: 它们是JNI中所定义的宏可以在jni.h这个头文件中查找到。
如果不这样命名,当把动态库加载进DVM的时候,通过JNIEnv *指针去查找Java Native方法对应的JNI方法的时候,就会找不到了。
3、NDK的介绍
(1)、NDK的简介
NDK全称为native development kit本地语言(C&C++)开发包。简单来说利用NDK,可以开发纯C&C++的代码,然后编译成库,让Java程序调用。NDK开发的可以称之为底层开发或者jni(java native interface)层开发。
NDK是一系列工具的集合,NDK提供了一系列的工具,可以帮助开发者进行c/c++的开发,并能自动将.so打包成apk。NDK集成了交叉编译器,并提供了相应的mk文件可以做到隔离CPU,平台,ABI等差异,只需修改mk文件即可。开发人员只需要简单修改mk文件,就可以创建出“.so”文件。NDK还提供了一份稳定的功能有限的API头文件声明。
(2)、NDK和JNI的关系
简单来说,NDK是工具,使用NDK可以更方便、快捷的开发JNI,NDK开发是基于JNI的。而JNI,是Java提出的协议,从Java1.1开始,JNI就已经是Java平台的一部分,它允许Java代码和其他语言写的代码进行交互,JNI开发便是基于此开发。
使用NDK开发JNI的步骤如下;
① JNI接口的设计;
② 使用C/C++实现本地方法;
③ 使用NDK生成JNI动态链接库.so文件;
④ 将动态链接库复制到Java/Android工程,调用,运行即可。
⑤ so文件生成步骤
⑥ so文件调用
(3)、NDK的配置
在android studio中下载NDK,然后在系统的环境变量中配置: 环境变量 PATH 下追加 :G:\AndroidSDK\ndk-bundle 这个表示NDK的位置。
4、so文件的生成步骤(有两种方法,这是方法一)
(1)、新建一个Android Studio 工程 JniTest,新建一个MyJni.java文件:
public class MyJni {
static {
System.loadLibrary("MyJni"); //链接后面生成的MYJni.so库
}
public native static String getString(); //native 方法是C语言中要实现的方法
}
(2)、通过将java文件生成.class文件,然后编译成.h文件,这里使用了extend tool来实现一步生成.h文件。
配置javah和ndk-build: 在setting中选择extend tool,然后添加javah 命令的配置(一键生成h文件)
参数:
Program: $JDKPath$\bin\javah.exe 这里配置的是javah.exe的路径(基本一致)
$JDKPath$可以从右侧按钮(insert mac...)中选择
Parametes: $FileClass$ 这里指的是要编译.h文件的java类 (注意这里只填写了FileClass,其他参数没有导入那么自定义的一些model,或者Android.jar中的类是不支持的,可以先生成h然后手动输入特殊的参数。 比如Bitmap,在native方法中先不传这个参数,当生成h文件后,手动添加一个jobject的参数)
Working: ModuleFileDir\src\main\java //工作路径,也是.h生成的路径
通过右键需要生成.h文件的MyJni 类然后找extend tool中的javah,点击就可以获得在Main文件夹下Java文件夹下jni文件夹下对应的.h文件,其中就包含了java中要实现的getString方法。
(2)、在jni文件夹下新建一个C语言程序:
#include <stdio.h>
#include <jni.h>
#include <wu_com_ndktest_JNIUtils.h>
JNIEXPORT jstring JNICALL Java_wu_com_ndktest_JNIUtils_getString
(JNIEnv *env, jclass jclass){ //实现.h文件中的方法,返回字符串
//返回一个字符串
return (*env)->NewStringUTF(env,"This is my first NDK Application");
}
(3)、在jni文件夹下新建Android.mk和Application.mk文件。
Android.mk:
LOCAL_PATH := $(call my-dir) //固定写法,把路径赋给LOCAL_PATH变量
include $(CLEAR_VARS) //清除其他LOCAL变量
LOCAL_MODULE := JNITest //这个模块的名字,最后生成的.so的名字就是它,要跟java里面的loadLibray的名字一样。
LOCAL_SRC_FILES :=test.c\ //这里是要编译的文件,\ 符号是换行,可以有多个
include $(BUILD_SHARED_LIBRARY) //SHARED_LIBRARY就是动态库,即.so文件
Application.mk:
APP_ABI := all / /生成在什么架构下的.so文件,all指所有架构都生成
(4)、在命令行下,cd到jni目录下,输入指令: ndk-build,等一会即可生成.so文件;当然也可以添加extend tool来实现。位于lib目录下,将其放到app/src/main/jniLibs目录下就能用了。
5、so文件的调用
找到libs下生成的各体系结构下的.so库文件,然后把.so文件复制出来,放到需要使用的程序的Main的JAVA下新建的libs文件夹下:
(1)、把复制的so包,放到项目的libs目录下
(2)、在app module 下的buide.gradle 中添加下面代码:
//放在libs目录中
sourceSets {
main {
jni.srcDirs=[] //使用自己编写的两个mk文件,避免android studio想自动生成而导致错误。
jniLibs.srcDirs = ['src/main/libs'] //libs表示libs文件夹的地址,一定要保证正确
}
}
这样就可以在安卓中使用c语言或者c++语言了。
6、Android studio使用CMake生成”so”文件:
(1)、使用CMake构建native项目,使用CMake的话,必须要有CMakeLists.txt(注意名字不能写错),以及对应的cpp资源;在新建项目的时候把 include C++ support 勾选上就可以了,这样在MainActivity终就会生成对应的native方法对应Main文件夹下cpp文件夹的c或c++的文件方法,同样自己也可以定义需要的native方法,通过按alt+Enter就可以选择在c或c++文件中生成对应的方法,就可以在里面实现对应的代码逻辑。而CMakeLists.txt在App文件夹下,如果有需要的话,可以修改里面内容,CMakeLists.txt的内容如下:
# CMake最低版本 cmake_minimum_required(VERSION 3.4.1)
# 将需要打包的资源添加进来
add_library(
# 库名字
native_hello
# 库类型 表示编译生成的是动态链接库
SHARED
# 包含的cpp :表示编译文件的相对路径,这里可以是一个文件的路径也可以是多个文件的路径
native_hello.cpp )
# 链接到项目中
target_link_libraries(
native_hello
android
log )
(2)、当然上面介绍的是自动生成的c或c++,不过一般我们都是使用自定义的,这样才能符合自己的需求,方法如下:
AS已经提供了相对便捷的方法。首先在要使用jni调用的工程模块下新建一个
CMakeLists.txt:
代码:
cmake_minimum_required(VERSION 3.6)
add_library( # Sets the name of the library.
xjni
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/jni/XJni.c )
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.
xjni
# Links the target library to the log library
# included in the NDK.
${log-lib} )
CMakeLists.txt具体配置上面已经说过了,这个地方是去掉了注释了的。需要注意的是,如果我们不在c源代码文件中输出日志到logcat,那么我们是不需要依赖log库的,也就是说find_library、target_link_libraries不是必须的。
接着配置模块支持jni调用,对项目模块右键:
在弹出的提示框中选择刚新建配置的CMakeLists.txt文件:
看看app/build.gradle的变化:
编译完成,编译器会报找不到XJni.c文件错误。ok,那我们新建一个/app/src/main/jni/XJni.c:
只有一行代码,ok,再编译,没问题!接下来新建jni调用java文件XJni.java:
#include <jni.h>
public class XJni {
static {
System.loadLibrary("xjni");
}
public native String getStr(String s);
}
如果getStr方法显示错误红色,不用着急,选中函数名,按快捷键alt+enter:
选择create function后,函数就自动在XJni.c文件中生成了
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_test_jnitest4_XJni_getStr(JNIEnv *env, jobject instance, jstring s_) {
const char *s = (*env)->GetStringUTFChars(env, s_, 0);
// TODO
(*env)->ReleaseStringUTFChars(env, s_, s);
return (*env)->NewStringUTF(env, returnValue);
}
需要注意的是,最好让.java文件名与.c文件名同名,否则你可能快捷键不会出现create function选项。修改.c文件名的时候记得对应将CMakeLists.txt中修改。
最后这篇文章是借鉴了以下几位的心得:
https://blog.csdn/zxw136511485/article/details/53304258
https://blog.csdn/quwei3930921/article/details/78820991
还有不足,可以看这位大佬的引入第三方库:
https://blog.csdn/Xiongjiayo/article/details/85340121
版权声明:本文标题:Android中so文件的生成和调用 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1726385782h950074.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论