android studio 编译 jni 库并被调用(1)

文章目录

        • 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 选项

android studio 编译 jni 库并被调用(1)_第1张图片
当下载完全找到 ndk 路径 ,

android studio 编译 jni 库并被调用(1)_第2张图片
数字是下载的版本号
android studio 编译 jni 库并被调用(1)_第3张图片

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 进行设置
android studio 编译 jni 库并被调用(1)_第4张图片

3 编译自身 so 库文件

1) 新建 Android studio 项目
2) 新建 一个 java 层 JNI 类

新建 一个类 用来声明 是 一个 JNI 接口,通过这个 类来进行 库的加载 和 C/C++ 函数的调用

android studio 编译 jni 库并被调用(1)_第5张图片

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

在这里插入图片描述
android studio 编译 jni 库并被调用(1)_第6张图片
android studio 编译 jni 库并被调用(1)_第7张图片

4) main 文件夹 下新建 jni 文件

android studio 编译 jni 库并被调用(1)_第8张图片

5) 编写 对应的 C 文件 ,和编译用到的 mk 文件

1) 将上面 生成的 .h 文件移到到 新建的 jni 文件夹 中
2) 在 jni 文件中 新建 native.c 文件,编写功能函数
android studio 编译 jni 库并被调用(1)_第9张图片
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);
}
  1. 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 哭架构 

android studio 编译 jni 库并被调用(1)_第10张图片

6) 编译 so 库

(1) android studio 命令行模式 切换到 jni 目录
在这里插入图片描述
(2) 执行 命令

 ndk-build

在这里插入图片描述
说明 已经帮我们编译好了 so 库
在 libs 文件之中
android studio 编译 jni 库并被调用(1)_第11张图片

7) gradle 添加 so 库的 引用位置

android studio 编译 jni 库并被调用(1)_第12张图片

    //添加
    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 运行测试
android studio 编译 jni 库并被调用(1)_第13张图片
我们可以看到 我们 java 上层 已经能够 调用到 我们C 语言 编写的 函数 。

6、把自己的so 库给别人使用

把自己的so 库给别人用,需要给别人提供 so库的创建文件的 包名,以及对应java 层的方法说明
android studio 编译 jni 库并被调用(1)_第14张图片我们可以知道
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)库

你可能感兴趣的:(Android,进阶)