Android使用android studio配置并运行Jni详细流程
前言:
本文章以Android Studio为IDE,以手动编译不使用cmake的方式为例,在某个已有普通android项目基础上,创建jni程序并运行。详细介绍以下内容:
1、环境配置(Android Studio、SDK、JDK、NDK、Gradle)
2、创建java中的jni程序
3、根据java中的jni程序生成头文件,创建c/c++文件,创建配置文件
4、打包生成 *.so 库文件
5、配置项目引用创建好的 *.so 库文件并运行
6、External Tools 工具的配置和使用
准备好了吗?现在开干!
1、环境配置:首先电脑环境为 Windows10 64位操作系统,mac系统暂不涉及。由于Android Studio与Gradle,SDK,NDK,JDK的版本兼容问题,特意使用如下版本进行配置
Android Studio 4.0.2
SDK 30
NDK 21.3.6528147
JDK 1.8
1.1、Android Studio
Android Studio 下载文件归档 | Android 开发者 | Android Developers (google.cn)
进入网站,滚动到底部,点击“我同意这些条款”
然后在浏览器打开的界面中搜索 4.0.2
下载并安装好Android Studio后,第一次打开可能报错,不要急,复制错误内容搜索一下,很简单就能解决。正常打开Android Studio后,新建一个项目或者导入一个已有项目,在此不做过多说明。
1.2、SDK:这里只对我的SDK版本做说明,不代表其他版本不可
1.3、JDK:这里我使用JDK 1.8,不代表其他版本不可
官网下载地址:Java Downloads | Oracle
1.4、NDK:具体的NDK配置流程可以自行查询,网上很多。我使用的NDK版本为 21.3.6528147
1.5、Gradle:其他的Gradle版本未测试,这里贴出我使用的构建版本
1.5.1、gradle-wrapper.properties
打开文件,配置项如下
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
1.5.2、Project -> build.gradle
打开文件,配置项如下
classpath 'com.android.tools.build:gradle:4.0.2'
2、创建java中的jni程序:先创建一个类,在类中分别加入“静态加载so文件的程序”和“定义的native方法”
注意:包名类名方法名定义好后,不要随意更改,后面需要生成对应的头文件
package com.ndktest.jnilib;public class MyJniTest { static { System.loadLibrary("jniTestSo"); } public static native int getAddData(int a, int b); public static native String getStringFromJni();}
根据java中的jni程序生成头文件,创建c/c++文件,再创建两个配置文件Application.mk、Android.mk
3.1、根据 MyJniTest 类生成对应的头文件
在terminal中cd到 app/class="lazy" data-src/main/java 目录下
执行以下命令
javah -encoding utf-8 -d ../jni -jni com.ndktest.jnilib.MyJniTest
正确执行后,切换Android Studio中的导览图类型为project,在class="lazy" data-src/main/java同级别的jni目录下就能看到生成的头文件 com_ndktest_jnilib_MyJniTest.h
打开 com_ndktest_jnilib_MyJniTest.h 文件,可以看到里面会定义出我们定义的native方法所对应的头文件中的方法,这里不需要做任何修改
3.2、根据头文件创建对应的 c/c++ 文件:
在头文件所在的jni目录:右键 -> New -> File
命名为 demo.c
在 demo.c 文件中导入头文件,加入头文件中方法的实现
//// Created by wct on 2023/5/8.////#include #include "com_ndktest_jnilib_MyJniTest.h"JNIEXPORT jint JNICALLJava_com_ndktest_jnilib_MyJniTest_getAddData(JNIEnv *env, jclass thiz, jint a, jint b) { return a + b;}JNIEXPORT jstring JNICALLJava_com_ndktest_jnilib_MyJniTest_getStringFromJni(JNIEnv *env, jclass thiz) { return (*env)->NewStringUTF(env, "Hello World from c++");}
3.3、创建对应的配置文件 Application.mk
在头文件所在的jni目录:右键 -> New -> File
命名为 Application.mk
再把相关配置属性加入其中,可直接复制下面的代码到 Application.mk
# Application.mk 参数# 默认生成支持的多种类型.soAPP_ABI := all# APP_PLATFORM := android-16不配置,打包.so会出错APP_PLATFORM := android-16# 可选项,如果没有定义,则NDK编译所有Android.mk中的modules.如果定义了,则只编译Android.mk中被APP_MODULES指定的模块以及他们所依赖的模块。APP_MODULES := jniTestSo
3.4、创建对应的配置文件 Android.mk
在头文件所在的jni目录:右键 -> New -> File
命名为 Android.mk
再把相关配置属性加入其中,可直接复制下面的代码到 Android.mk
# Android.mk 参数# 设置工作目录,它用于在开发tree中查找源文件。宏my-dir由Build System提供,会返回Android.mk文件所在的目录LOCAL_PATH := $(call my-dir)# CLEAR_VARS变量由Build System提供。指向一个指定的GNU Makefile,由它负责清理LOCAL_xxx类型文件,但不是清理LOCAL_PATH# 所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能便面相互影响,这一操作必须有include $(CLEAR_VARS)# LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块,名字必须唯一且不包含空格# Build System 会自动添加适当的前缀和后缀。例如,demo,要生成动态库,则生成libdemo.so。但请注意:如果模块名字被定义为libabc,则生成libabc.so。不再添加前缀。LOCAL_MODULE := jniTestSo# 指定参与模块编译的C/C++源文件名。不必列出头文件,build System 会自动帮我们找出依赖文件。缺省的C++ 源码的扩展名为.cppLOCAL_class="lazy" data-src_FILES =: demo.c# BUILD_SHARED_LIBRARY是Build System提供的一个变量,指向一个GUN Makefile Script。它负责收集自从上次调用include $(CLEAR_VARS)后的所有LOCAL_xxxxinx。并决定编译什么类型# 1. BUILD_STATIC_LIBRARY:编译为静态库# 2. BUILD_SHARED_LIBRARY:编译为动态库# 3. BUILD_EXECUTABLE:编译为Native C 可执行程序# 4. BUILD_PREBUILT:该模块已经预先编译include $(BUILD_SHARED_LIBRARY)
4、打包生成 *.so 库文件:这里我在Android.mk中配置属性 LOCAL_MODULE := jniTestSo,因此生成的so文件名为 libjniTestSo.so,生成的方式如下
在terminal中cd到 app/class="lazy" data-src/main/java 目录下
执行以下命令
ndk-build
正确执行后,切换Android Studio中的导览图类型为project,在class="lazy" data-src/main/java同级别的libs目录下就能看到生成的两个文件夹 libs 和 obj,其中class="lazy" data-src/main/libs文件夹下就能看到不同ABI对应的so库文件
5、配置已有项目引用创建好的 *.so 库文件并运行:
5.1、复制生成的so库文件到项目指定目录:
找到设备对应可用的ABI类型,这里我的设备支持的ABI为 arm64-v8a,因此只需要把 class="lazy" data-src/main/libs 下的 arm64-v8a 文件夹拷贝到 app/libs 目录中,如果你的设备支持其他的ABI类型,复制对应的文件即可
5.2、打开 Module 中的 build.gradle 文件,在 buildTypes 中增加 sourceSets 配置
buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } // 加载本地so文件配置(必选) sourceSets { main { jniLibs.class="lazy" data-srcDir(['libs']) } } }
5.3、打开 gradle.properties 文件,添加 android.useDeprecatedNdk 属性
# 添加对旧版本的NDK支持,此项目使用NDK版本=21.3.6528147,不配置以下参数也可android.useDeprecatedNdk=true
5.4、测试调用 MyJniTest 类中的 jni 方法
// 测试jni调用so库方法int getAddData = MyJniTest.getAddData(2, 6);String getStringFromJni = MyJniTest.getStringFromJni();textView_message.setText("getAddData=" + getAddData + "\ngetStringFromJni=" + getStringFromJni);
5.5、运行程序:我这里使用Android Studio连接真机直接运行
上图中输出的结果分别对应我在 demo.c 文件中的方法实现
6、External Tools 工具的配置和使用:配置一次,终生幸福(借用前人的一句话)
在上述 3.1生成头文件 和 4生成so库文件 的过程中,都使用到了Android Studio自带的命令行工具,分别执行了 javah 和 ndk-build 命令。Android Studio 还为我们提供了另一种执行终端命令的工具,就是External Tools,它可以帮助我们更简单的实现 3.1 和 4 中的工作。
6.1、配置 External Tools -> javah
点击 Android Studio 中的 File -> settings,在打开面板的搜索栏中输入 External Tools,选中Tools 下的 External Tools,再点击 +号,填写如下配置,再点击 “OK”按钮保存
Program:// 这里改为你的 JDK 中 bin 目录下面的 javah.exe 文件目录C:\Program Files\Java\jdk-1.8\bin\javah.exeArguments:// 不用改,直接复制即可-encoding UTF-8 -d ../jni -jni $FileClass$Working directory:// 不用改,直接复制即可$ProjectFileDir$\app\class="lazy" data-src\main\java
6.2、配置 External Tools -> ndk-build
继续点击 +号,填写如下配置,再点击“OK”按钮保存
Program:// 这里改为你的 NDK 对应的 ndk-build.cmd 文件目录$ModuleSdkPath$/ndk-bundle/21.3.6528147/ndk-build.cmdArguments:// 指定输出so库文件的目录,不用改,直接复制即可NDK_LIBS_OUT=$ProjectFileDir$\app\class="lazy" data-src\main\libsWorking directory:// 不用改,直接复制即可$ProjectFileDir$\app\class="lazy" data-src\main
6.4、使用 External Tools -> ndk-build
在上述 3.1 生成头文件时,右键点击要生成头文件对应的类,然后依次选中
External Tools -> javah
6.3、使用 External Tools -> ndk-build
在上述 4 生成so文件时,右键点击 class="lazy" data-src/main 下面的 jni 目录,然后依次选中
External Tools -> ndk-build
写在最后,如果你跟着上面的步骤,运行出了自己的jni程序,相信过程中也一定有所收获,码字不易,与君共勉!
来源地址:https://blog.csdn.net/yxw331291779/article/details/130573009
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341