文章目录
- 1、简介
- 1)、NDK
- 2) 、为什么使用NDK?
- 3)什么是JNI?
- 4) 为什么使用JNI?
- 2、环境配置
- 1)android studio ndk 下载
- 2) ndk 路径配置
- (1)ubuntu 配置 ndk 全局路径
- (2)android studio 配置 NDK
- 3 编译自身 so 库文件
- 1) 新建 Android studio 项目
- 2) 新建 一个 java 层 JNI 类
- 3) javah 生成JNI 类 能够 和C /C++ 文件相互引用的头文件
- 4) main 文件夹 下新建 jni 文件
- 5) 编写 对应的 C 文件 ,和编译用到的 mk 文件
- 6) 编译 so 库
- 7) gradle 添加 so 库的 引用位置
- 4、主函数 调用 so 库
- 5、运行测试
- 6、把自己的so 库给别人使用
1、简介
1)、NDK
NDK全称是Native Development Kit,NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。NDK集成了交叉编译器(交叉编译器需要UNIX或LINUX系统环境),并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
2) 、为什么使用NDK?
1.)代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
2.)可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
3.)提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
4.)便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。
3)什么是JNI?
JNI全称为:Java Native Interface。JNI是本地编程接口,它使得在 Java 虚拟机内部运行的 Java代码能够与用其它语言(如 C、C++)编写的代码进行交互。
4) 为什么使用JNI?
JNI的目的是使java方法能够调用c实现的一些函数。
2、环境配置
1)android studio ndk 下载
在 android studio 里 sdk manager 里面 勾选 NDK 选项
当下载完全找到 ndk 路径 ,
数字是下载的版本号
2) ndk 路径配置
(1)ubuntu 配置 ndk 全局路径
gedit ~/.bashrc
最后添加 这两句
export NDK=/home/user/Android/Sdk/ndk/21.3.6528147 (自己ndk 路径)
export PATH=${PATH}:$NDK
刷新配置
source ~/.bashrc
运行 :
ndk-build
只要不是 command not find 就是已经配置好。
(2)android studio 配置 NDK
File — > Project Structure 进行设置
3 编译自身 so 库文件
1) 新建 Android studio 项目
2) 新建 一个 java 层 JNI 类
新建 一个类 用来声明 是 一个 JNI 接口,通过这个 类来进行 库的加载 和 C/C++ 函数的调用
package com.example.myjnitest;
public class JNICallerNative {
static {
System.loadLibrary("native"); //声明加载的类名
}
public static native String getStringFromNative(); //生命 要调用的c 函数返回的类型 和 java 层接口
}
3) javah 生成JNI 类 能够 和C /C++ 文件相互引用的头文件
(1)android studio 命令窗口 进入 项目 java 目录:
(2)输入javah -jni “包名.类名”,即会会java目录下生成头文件。
javah -jni com.example.myjnitest.JNICallerNative
4) main 文件夹 下新建 jni 文件
5) 编写 对应的 C 文件 ,和编译用到的 mk 文件
1) 将上面 生成的 .h 文件移到到 新建的 jni 文件夹 中
2) 在 jni 文件中 新建 native.c 文件,编写功能函数
native.c
//
// Created by lum on 20-8-6.
//
#include "com_example_myjnitest_JNICallerNative.h" //引入 上面编译的头文件
JNIEXPORT jstring JNICALL Java_com_example_myjnitest_JNICallerNative_getStringFromNative(JNIEnv *env, jobject obj){//方法名是Java_包名_类名_方法名 和 .h 文件中一样
char *str = "String from native C";
return (*env)->NewStringUTF(env, str);
}
- jni 目录 编写 ndk 编译 成 so 文件的 mk 文件
(1) 新建 Android.mk 文件
LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=native # 编译的 目标库
LOCAL_SRC_FILES :=native.c # 编译源文件
include $(BUILD_SHARED_LIBRARY)
(2)新建 Application.mk 文件
Application.mk
APP_MODULES := native # 编译 目标库
APP_ABI := armeabi-v7a # 编译的so 哭架构
6) 编译 so 库
(1) android studio 命令行模式 切换到 jni 目录
(2) 执行 命令
ndk-build
说明 已经帮我们编译好了 so 库
在 libs 文件之中
7) gradle 添加 so 库的 引用位置
//添加
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
jni.srcDirs = [] //disable automatic ndk-build call
}
4、主函数 调用 so 库
package com.example.myjnitest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import static com.example.myjnitest.JNICallerNative.getStringFromNative;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("jni call ",getStringFromNative()); // 主函数 调用我们 上层 封装的 JNICallerNative 里面的额方法
}
}
5、运行测试
安装 apk 运行测试
我们可以看到 我们 java 上层 已经能够 调用到 我们C 语言 编写的 函数 。
6、把自己的so 库给别人使用
把自己的so 库给别人用,需要给别人提供 so库的创建文件的 包名,以及对应java 层的方法说明
我们可以知道
Java_com_example_myjnitest_JNICallerNative_getStringFromNative
这个里面 就包含了 so 库的 包名 和方法名
包名路径 : com.example.myjnitest
创建的java 层文件 类:JNICallerNative.java
java 层调用的方法: getStringFromNative
以及 so 库支持什么 架构: armv7 x86 x86_64 等
知道了这些东西,别人调用的时候,才知道怎么引用,每个方法的使用方法。
android studio 编译 jni 调用标准的so库 (2)
文章参考:
Android Studio实现JNI,并编译出本地库So
Ubuntu下Android NDK安装与配置
Linux下使用NDK进行so库的编译和生成
Linux下gcc编译生成动态链接库*.so文件并调用它
android中调用共享库.so的几种方法
Android Studio打包生成so库并且在别的项目中引用
Android JNI (.so)库中与android共享第三方 (.so)库