当前位置:   article > 正文

Android使用android studio配置并运行Jni详细流程_android studio jni

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方法”

        注意:包名类名方法名定义好后,不要随意更改,后面需要生成对应的头文件

  1. package com.ndktest.jnilib;
  2. /**
  3. * jni方法工具类
  4. *
  5. * @author Wesley Yan
  6. */
  7. public class MyJniTest {
  8. static {
  9. System.loadLibrary("jniTestSo");
  10. }
  11. /**
  12. * 计算 a+b 的和
  13. * @param a int
  14. * @param b int
  15. *
  16. * @return int 返回 a+b 的结果值
  17. */
  18. public static native int getAddData(int a, int b);
  19. /**
  20. * 获取so库中的字符串
  21. */
  22. public static native String getStringFromJni();
  23. }

3、根据java中的jni程序生成头文件,创建c/c++文件,再创建两个配置文件Application.mk、Android.mk

3.1、根据 MyJniTest 类生成对应的头文件

        在terminal中cd到 app/src/main/java 目录下

        

        执行以下命令

        javah -encoding utf-8 -d ../jni -jni com.ndktest.jnilib.MyJniTest

        正确执行后,切换Android Studio中的导览图类型为project,在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 文件中导入头文件,加入头文件中方法的实现

  1. //
  2. // Created by wct on 2023/5/8.
  3. //
  4. //#include <jni.h>
  5. #include "com_ndktest_jnilib_MyJniTest.h"
  6. /*
  7. * Class: com_ndktest_jnilib_MyJniTest
  8. * Method: getAddData
  9. * Signature: (II)I
  10. */
  11. JNIEXPORT jint JNICALL
  12. Java_com_ndktest_jnilib_MyJniTest_getAddData(JNIEnv *env, jclass thiz, jint a, jint b) {
  13. return a + b;
  14. }
  15. /*
  16. * Class: com_ndktest_jnilib_MyJniTest
  17. * Method: getStringFromJni
  18. * Signature: ()Ljava/lang/String;
  19. */
  20. JNIEXPORT jstring JNICALL
  21. Java_com_ndktest_jnilib_MyJniTest_getStringFromJni(JNIEnv *env, jclass thiz) {
  22. return (*env)->NewStringUTF(env, "Hello World from c++");
  23. }

3.3、创建对应的配置文件 Application.mk

        在头文件所在的jni目录:右键 -> New -> File

        命名为 Application.mk

        再把相关配置属性加入其中,可直接复制下面的代码到 Application.mk

  1. # Application.mk 参数
  2. # 默认生成支持的多种类型.so
  3. APP_ABI := all
  4. # APP_PLATFORM := android-16不配置,打包.so会出错
  5. APP_PLATFORM := android-16
  6. # 可选项,如果没有定义,则NDK编译所有Android.mk中的modules.如果定义了,则只编译Android.mk中被APP_MODULES指定的模块以及他们所依赖的模块。
  7. APP_MODULES := jniTestSo

3.4、创建对应的配置文件 Android.mk

        在头文件所在的jni目录:右键 -> New -> File

        命名为 Android.mk

        再把相关配置属性加入其中,可直接复制下面的代码到 Android.mk

  1. # Android.mk 参数
  2. # 设置工作目录,它用于在开发tree中查找源文件。宏my-dir由Build System提供,会返回Android.mk文件所在的目录
  3. LOCAL_PATH := $(call my-dir)
  4. # CLEAR_VARS变量由Build System提供。指向一个指定的GNU Makefile,由它负责清理LOCAL_xxx类型文件,但不是清理LOCAL_PATH
  5. # 所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能便面相互影响,这一操作必须有
  6. include $(CLEAR_VARS)
  7. # LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块,名字必须唯一且不包含空格
  8. # Build System 会自动添加适当的前缀和后缀。例如,demo,要生成动态库,则生成libdemo.so。但请注意:如果模块名字被定义为libabc,则生成libabc.so。不再添加前缀。
  9. LOCAL_MODULE := jniTestSo
  10. # 指定参与模块编译的C/C++源文件名。不必列出头文件,build System 会自动帮我们找出依赖文件。缺省的C++ 源码的扩展名为.cpp
  11. LOCAL_SRC_FILES =: demo.c
  12. # BUILD_SHARED_LIBRARY是Build System提供的一个变量,指向一个GUN Makefile Script。它负责收集自从上次调用include $(CLEAR_VARS)后的所有LOCAL_xxxxinx。并决定编译什么类型
  13. # 1. BUILD_STATIC_LIBRARY:编译为静态库
  14. # 2. BUILD_SHARED_LIBRARY:编译为动态库
  15. # 3. BUILD_EXECUTABLE:编译为Native C 可执行程序
  16. # 4. BUILD_PREBUILT:该模块已经预先编译
  17. include $(BUILD_SHARED_LIBRARY)

4、打包生成 *.so 库文件:这里我在Android.mk中配置属性 LOCAL_MODULE := jniTestSo,因此生成的so文件名为 libjniTestSo.so,生成的方式如下

         在terminal中cd到 app/src/main/java 目录下

        

        执行以下命令

        ndk-build    

        正确执行后,切换Android Studio中的导览图类型为project,在src/main/java同级别的libs目录下就能看到生成的两个文件夹 libs 和 obj,其中src/main/libs文件夹下就能看到不同ABI对应的so库文件

5、配置已有项目引用创建好的 *.so 库文件并运行:

5.1、复制生成的so库文件到项目指定目录:

        找到设备对应可用的ABI类型,这里我的设备支持的ABI为 arm64-v8a,因此只需要把 src/main/libs 下的 arm64-v8a 文件夹拷贝到 app/libs 目录中,如果你的设备支持其他的ABI类型,复制对应的文件即可

5.2、打开 Module 中的 build.gradle 文件,在 buildTypes 中增加 sourceSets 配置

  1. buildTypes {
  2. release {
  3. minifyEnabled false
  4. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  5. }
  6. // 加载本地so文件配置(必选)
  7. sourceSets {
  8. main {
  9. jniLibs.srcDir(['libs'])
  10. }
  11. }
  12. }

5.3、打开 gradle.properties 文件,添加 android.useDeprecatedNdk 属性

  1. # 添加对旧版本的NDK支持,此项目使用NDK版本=21.3.6528147,不配置以下参数也可
  2. android.useDeprecatedNdk=true

5.4、测试调用 MyJniTest 类中的 jni 方法

  1. // 测试jni调用so库方法
  2. int getAddData = MyJniTest.getAddData(2, 6);
  3. String getStringFromJni = MyJniTest.getStringFromJni();
  4. 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”按钮保存

  1. Program:
  2. // 这里改为你的 JDK 中 bin 目录下面的 javah.exe 文件目录
  3. C:\Program Files\Java\jdk-1.8\bin\javah.exe
  4. Arguments:
  5. // 不用改,直接复制即可
  6. -encoding UTF-8 -d ../jni -jni $FileClass$
  7. Working directory:
  8. // 不用改,直接复制即可
  9. $ProjectFileDir$\app\src\main\java

6.2、配置 External Tools -> ndk-build

继续点击 +号,填写如下配置,再点击“OK”按钮保存

  1. Program:
  2. // 这里改为你的 NDK 对应的 ndk-build.cmd 文件目录
  3. $ModuleSdkPath$/ndk-bundle/21.3.6528147/ndk-build.cmd
  4. Arguments:
  5. // 指定输出so库文件的目录,不用改,直接复制即可
  6. NDK_LIBS_OUT=$ProjectFileDir$\app\src\main\libs
  7. Working directory:
  8. // 不用改,直接复制即可
  9. $ProjectFileDir$\app\src\main

6.4、使用 External Tools -> ndk-build

        在上述 3.1 生成头文件时,右键点击要生成头文件对应的类,然后依次选中 

        External Tools -> javah

6.3、使用 External Tools -> ndk-build

        在上述 4 生成so文件时,右键点击 src/main 下面的 jni 目录,然后依次选中 

        External Tools -> ndk-build

 

        写在最后,如果你跟着上面的步骤,运行出了自己的jni程序,相信过程中也一定有所收获,码字不易,与君共勉!

        

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/953234
推荐阅读
相关标签
  

闽ICP备14008679号