超详细的Android NDK开发环境搭建(2)

其他细节

===================================================================

1、自动生成native方法


完成上面的例子后,如果还想再增加第二个native方法时,可以使用自动生成功能,如在MainActivity中添加一个add方法,如下:


external fun add(x: Int, y: Int): Int



此时会报错,把光标定位到add上,按Alt + Enter,选择创建jni函数即可,如下:

在这里插入图片描述

此时就会自动在demo.cpp中增加对应的jni函数,如下:


extern "C"

JNIEXPORT jint JNICALL

Java_com_even_app_ndkdemo_MainActivity_add(JNIEnv *env, jobject thiz, jint x, jint y) {

    // TODO: implement add()

}



在创建第一个jni函数的时候无法使用此方式来自动生成,这应该算是AndroidStudio的一个Bug吧,只有手动写了一个jni函数之后,第二个才会出现创建jni函数的命令。

2、使用创建向导生成带ndk的项目


File > New > New Project > Native C++,此时可能会报一个错,如下:

在这里插入图片描述

错误说的是NDK没有配置,这应该也算AndroidStudio的一个Bug吧,我已经安装有NDK,有好几个版本(包含最新版本),AndroidStudio应该自动给我选一个,用最新的也行。上面描述说的意思是首选的NDK版本是21.0.6113669,我并没有安装这个版本,所以它提示我们安装,其实没有必要安装这个版本的,按Ctrl + Shift + Alt + S打开项目结构,在弹出来的对话框中设置一个已经安装的NDK位置即可。然后就可以直接运行查看效果了。

如果是要做一个新项目,这样的方式创建NDK项目非常方便。

使用向导创建的NDK项目还会在app下的build.gradle中多一个cppFlag的配置,如下:


android {



    defaultConfig {

        externalNativeBuild {

            cmake {

                cppFlags ""

            }

        }

    }

	

}



这个应该是用于指定C++的版本,cppFlags为空,这是因为我在创建这个项目的向导中选择的C++版本时选择了默认,如下:

在这里插入图片描述

点击下拉箭头,可以看到我们当前设置的NDK的版本所支持的C++版本,不同的NDK版本可能会支持不同的C++版本,截图如下:

在这里插入图片描述

假如我们选择C++17,则cppFlag属性如下:


android {



    defaultConfig {

        externalNativeBuild {

            cmake {

                cppFlags "-std=c++17"

            }

        }

    }

	

}



3、查看生成的so文件


a、通过生成的apk中提取

直接在AndroidStudio中运行项目时,AndroidStudio会根据手机的CPU类型来生成对应的CPU架构的so文件。点击Build > Analyze APK,在弹出来的对话框中选择app\build\outputs\apk\debug\app-debug.apk,这样就能看到apk文件的内部结构了,如下:

在这里插入图片描述

因为我的手机CPU是arm64-v8a结构的,所以直接运行时它只生成和手机对应的so文件,如果想要生成所有的,可以点击Build > Build Bundle(s) / APK(s) > Build APK(s),这样的话也会生成debug.apk,但是这个apk并不针对哪一个手机,所以会生成所有的so,如下:

在这里插入图片描述

这里说的所有的so是指特定NDK版本支持的so CPU类型,从NDK 17开始,不再支持armeabi,所以上图中没有看到armeabi的so。为什么不支持armeabi了呢?因为现在的手机基本上都支持armeabi-v7a了。

如果只想配置生成特定的so类型,可以在app下的build.gradle中设置如下:


android {

    

    defaultConfig {

        ndk {

            // Specifies the ABI configurations of your native

            // libraries Gradle should build and package with your APK.

            abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'

        }

    }



}



从apk中提取so文件很容易,把apk扩展名改成rar,然后用压缩软件解压即可。

b、通过build目录中获取

通过生成apk,从apk中获取是比较容易记的,从build目录中就需要记一下目录结构,有时候会记不住,但是也没关系,记不住的时候就从apk中取so嘛。

在Build Variants面板中选择release版本,默认是debug版本,不知道有什么区别,但是选release肯定是比较正规嘛,准没错。然后执行菜单命令:Build/Build Bundle(s)/Apk(s)/Build Apk(s),这样就会生成一个release版本的apk,是一个没有签名的apk(如果gradle文件中没有配置签名的话),生成apk的同时也会生成对应的so文件,在如下位置:

在这里插入图片描述

4、相关连接


NDK入门:https://developer.android.google.cn/ndk/guides

代码实验室:https://codelabs.developers.google.com/codelabs/android-studio-cmake/#0

Github上提供的NDK Demo:https://github.com/android/ndk-samples

关于CMake:https://developer.android.com/ndk/guides/cmake.html

配置CMake:https://developer.android.google.cn/studio/projects/configure-cmake#add-ndk-api

添加native代码:https://developer.android.google.cn/studio/projects/add-native-code

JNI相关:https://developer.android.google.cn/training/articles/perf-jni

JNI接口规范:https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html

5、关于生成so文件到jniLibs目录


jniLibs目录在main目录下,如:

在这里插入图片描述

以前我们都是把so文件放到jniLibs目录中来使用,现在好了,打包时直接编译源码为so并打包到apk。人有时候就是想使用原来的方式,网上找了一下,在CMakeLists.txt中加入下面这句代码:


# 设置so文件输出到jniLibs目录中

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})



在AndroidStudio中直接运行应用,确实会在jniLibs目录中生成对应的so文件了,但是报一个错误,如下:

More than one file was found with OS independent path ‘lib/armeabi-v7a/libdemo-lib.so’. If you are using jniLibs and CMake IMPORTED targets, see https://developer.android.com/studio/preview/features#automatic_packaging_of_prebuilt_dependencies_used_by_cmake

提示中有一个链接,但是点击这个连接之后找不到相关的内容,应该是Google重新编辑网页,删除掉了,这个链接是跳转到AndroidStudio4.1的新特性的,在这里面会有“Automatic packaging of prebuilt dependencies used by CMake”的相关内容,但是已经被编辑掉了,在Google中搜索这段英文时能找到链接,但是要点快照,出来的网页就会有需要的内容,这里把原文搬过来,并配上翻译如下:

Automatic packaging of prebuilt dependencies used by CMake

自动打包CMake使用的预构建依赖项

Prior versions of the Android Gradle Plugin required that you explicitly package any prebuilt libraries used by your CMake external native build by using jniLibs:

早期版本的Android Gradle插件要求您使用以下命令显式打包CMake外部本机内部版本使用的所有预构建库 jniLibs:


sourceSets {

    main {

        // The libs directory contains prebuilt libraries that are used by the

        // app's library defined in CMakeLists.txt via an IMPORTED target.

        // libs目录包含预构建的库,这些库由CMakeLists.txt中通过导入目标定义的应用程序库使用。

        jniLibs.srcDirs = ['libs']

    }

}



With Android Gradle Plugin 4.0, the above configuration is no longer necessary and will result in a build failure:

使用Android Gradle Plugin 4.0时,不再需要上述配置,并且会导致构建失败:

What went wrong:

Execution failed for task ‘:app:mergeDebugNativeLibs’.

A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade

More than one file was found with OS independent path ‘lib/x86/libprebuilt.so’

External native build now automatically packages those libraries, so explicitly packaging the library with jniLibs results in a duplicate. To avoid the build error, simple remove the jniLibs configuration from your build.gradle file.

现在,外部本机构建会自动打包这些库,因此将jniLibs结果与库明确打包在一起。为避免生成错误,只需jniLibs从build.gradle文件中删除配置即可。

6、在C中使用Logcat打印日志


使用AndroidStudio的向导创建的NDK项目,默认就已经导入了Logcat库,如下:

在这里插入图片描述

如上图,画红圈的即为在C中引入Logcat相关设置,这是向导自动创建的,也可以删掉注释,简化一下,如下:

在这里插入图片描述

在C源文件中添加如下代码:


#include <android/log.h>

#define LOG_TAG "JNI"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)



然后就可以调用LOGD或LOGI来打印日志了,如下:


extern "C"

JNIEXPORT jint JNICALL

Java_cn_android666_nativehello_MainActivity_add(JNIEnv *env, jobject thiz, jint x, jint y) {

    LOGI("x = %d", x); // 使用语法和printf()函数是一样的

    LOGD("y = %d", y);

    LOGI("Hello World!");

    return x + y;

}




#### 最后笔者收集整理了一份Flutter高级入门进阶资料PDF

以下是资料目录和内容部分截图

> ![](https://img-blog.csdnimg.cn/img_convert/9c75367fde416108240a14bae21c2c7d.webp?x-oss-process=image/format,png)
> ![](https://img-blog.csdnimg.cn/img_convert/d7f8a36f266fb75822d09b2b73b64348.webp?x-oss-process=image/format,png)
> 里面包括详细的知识点讲解分析,带你一个星期入门Flutter。还有130个进阶学习项目实战视频教程,让你秒变大前端。



> ![](https://img-blog.csdnimg.cn/img_convert/a5752818933a3915f6667275ba63a5b2.webp?x-oss-process=image/format,png)



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

kWE-1714695983966)]
> [外链图片转存中...(img-lo8PKkwK-1714695983966)]
> 里面包括详细的知识点讲解分析,带你一个星期入门Flutter。还有130个进阶学习项目实战视频教程,让你秒变大前端。



> [外链图片转存中...(img-WKpvaSXd-1714695983967)]



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值