NDK全称是Native Development Kit,NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。NDK集成了交叉编译器(交叉编译器需要UNIX或LINUX系统环境),并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
1.)代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
2.)可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
3.)提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
4.)便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。
JNI全称为:Java Native Interface。JNI是本地编程接口,它使得在 Java 虚拟机内部运行的 Java代码能够与用其它语言(如 C、C++)编写的代码进行交互。
JNI的目的是使java方法能够调用c实现的一些函数。
在 android studio 里 sdk manager 里面 勾选 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 就是已经配置好。
File — > Project Structure 进行设置
新建 一个类 用来声明 是 一个 JNI 接口,通过这个 类来进行 库的加载 和 C/C++ 函数的调用
package com.example.myjnitest;
public class JNICallerNative {
static {
System.loadLibrary("native"); //声明加载的类名
}
public static native String getStringFromNative(); //生命 要调用的c 函数返回的类型 和 java 层接口
}
(1)android studio 命令窗口 进入 项目 java 目录:
(2)输入javah -jni “包名.类名”,即会会java目录下生成头文件。
javah -jni com.example.myjnitest.JNICallerNative
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);
}
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 哭架构
(1) android studio 命令行模式 切换到 jni 目录
(2) 执行 命令
ndk-build
//添加
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
jni.srcDirs = [] //disable automatic ndk-build call
}
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 里面的额方法
}
}
安装 apk 运行测试
我们可以看到 我们 java 上层 已经能够 调用到 我们C 语言 编写的 函数 。
把自己的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)库