Android NDK开发入门2之适应idm环境
环境搭建
Android NDK开发实战之环境搭建篇(so库,Gemini ai)-CSDN博客
初始配置
前面已经运行了一个简单的初始程序,现在我们来往初始程序添加类和函数,并成功运行的实验。
一级配置
第一层配置主要是cmake文件环境和一些编译选项。

build配置 可参考:
#build配置externalNativeBuild {cmake {path file('src/main/cpp/CMakeLists.txt')version '3.22.1'//cpp 编译选项cppFlags '-fexceptions -std=c++11'//设置c++stl为动态库 默认是静态库 arguments '-DANDROID_STL=c++_shared'}}


二级cmake配置
主要配置生成的动态库名称,具体看注释
为了测试 我们创建一个hello类
#include "iostream"
class hello {
public:std::string getVersion();
};
#include "hello.h"
std::string hello::getVersion(){return "v1.0 hello word";
}
#include <jni.h>
#include <string>#include "hello.h"
extern "C" JNIEXPORT jstring JNICALL
//stringFromJNI是c++function名称
Java_com_example_first_1ndk_1cpp_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {std::string helo = "Hello from first native C++ ";hello h;helo += h.getVersion();return env->NewStringUTF(helo.data());
}
更改cmake,把cpp文件加入
#cmake最低版本
cmake_minimum_required(VERSION 3.22.1)#最终项目名称 通过${CMAKE_PROJECT_NAME}获得
project("first_ndk_cpp")add_library(#生成的动态库名称${CMAKE_PROJECT_NAME}#生成库类型:SHARED动态 默认静态SHARED#相关cpp文件 假设有全局变量,交叉使用需要注意编译顺序。native-lib.cpphello.cpp)target_link_libraries(#最终生成目标库名称${CMAKE_PROJECT_NAME}# 链接其他目标库androidlog)
MainActivity
MainActivity 通常被认为是 Android 应用程序的主要入口点。

public class MainActivity extends AppCompatActivity {// 静态初始化块, 程序启动时调用static {//加载名为 first_ndk_cpp 的动态库System.loadLibrary("first_ndk_cpp");}private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//视图绑定binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());// Example of a call to a native methodTextView tv = binding.sampleText;tv.setText(stringFromJNI()); //java调用}/**这声明了一个名为 stringFromJNI 的本地方法。该实现位于 first_ndk_cpp 库中。*/public native String stringFromJNI();
}
运行
最后运行输出

小结
熟悉基本配置,知道增加类代码如何重新编译成动态库使用。
动态库实战
场景:编译两份版本动态库 分别输出v1和v2,然后切换运行。
设置动态库导出路劲
前面操作,我们成功编译出动态库。但是路劲很隐蔽,其次规范处理。

实现方法
CMakeLists.txt 设置导出so路劲:
CMAKE_ARCHIVE_OUTPUT_DIRECTORY :默认存放静态库的⽂件夹位置; CMAKE_LIBRARY_OUTPUT_DIRECTORY :默认存放动态库的⽂件夹位置;
# 第一种做法:单独设置动态库的默认输出路径
# 将动态库输出到 `main/jniLibs/${ANDROID_ABI}` 目录
# ${ANDROID_ABI} 是 Gradle 配置的 ABI 策略(如 armeabi-v7a, arm64-v8a 等)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY${CMAKE_CURRENT_SOURCE_DIR}/../libs/jniLibs/${ANDROID_ABI})# 第二种做法:设置动态库和静态库的默认输出路径
# 将动态库和静态库输出到 `main/jniLibs/${ANDROID_ABI}` 目录
# 注意:LIBRARY_OUTPUT_PATH 是旧版 CMake 的变量,
#推荐使用 CMAKE_LIBRARY_OUTPUT_DIRECTORY 和 CMAKE_ARCHIVE_OUTPUT_DIRECTORY
set(LIBRARY_OUTPUT_PATH${CMAKE_CURRENT_SOURCE_DIR}/../libs/jniLibs/${ANDROID_ABI})


根据这个方法步骤编译两个版本
主要区别:
std::string hello::getVersion(){return "v2.0 hello word";
}

尝试版本切换

//定义项目的源代码和资源文件的目录结构sourceSets {main {//指定 JNI 库文件(.so 文件)的存放目录jniLibs.srcDirs = ['src/main/libs/jniLibs']}}
小结
学习如何指定动态库导出路劲,并根据动态库切换,实现多种版本调用。
特定cpu架构实战
上述讨论了如何导出不同的动态库,现在如果只想根据x86架构导出单个so库如何实现?
先看看为什么需要指定cpu
⽣成指定cpu平台对应的so库⽂件

应⽤⼆进制接⼝(ABI),包含的内容:
1、可执⾏⼆进制⽂件的格式以及⽀持的内容类型,⼆进制⽂件如:程序、共享库...
2、可使⽤的CPU指令集
3、运⾏时内存存储和加载的字节顺序
4、应⽤和系统之间传递数据的规范,以及系统调⽤函数时,如何使⽤堆栈、寄存器
5、如何重整C++名称
abi与 指令集

Android 支持多种 CPU 架构,每种架构对应不同的 ABI。以下是常见的 CPU 架构及其对应的 ABI:
| CPU 架构 | ABI | 说明 |
|---|---|---|
| ARMv5 | armeabi | 32 位 ARM 架构,已过时,Android NDK r17 已不再支持。 |
| ARMv7 | armeabi-v7a | 32 位 ARM 架构,支持硬件浮点运算和 NEON 指令集。 |
| ARMv8 | arm64-v8a | 64 位 ARM 架构,支持 AArch64 指令集。 |
| MIPS | mips | 32 位 MIPS 架构,已过时,Android NDK r17 已不再支持。 |
| MIPS64 | mips64 | 64 位 MIPS 架构,已过时,Android NDK r17 已不再支持。 |
| x86 | x86 | 32 位 Intel x86 架构,主要用于模拟器和部分低端设备。 |
| x86_64 | x86_64 | 64 位 Intel x86 架构,主要用于模拟器和高性能设备。 |
ABI 兼容性是指应用程序在不同 CPU 架构上的运行能力。以下是各 ABI 的兼容性说明:
| ABI | 兼容性说明 |
|---|---|
armeabi | 兼容 ARMv5 和 ARMv7,但不兼容 ARMv8(64 位)。 |
armeabi-v7a | 兼容 ARMv7,但不兼容 ARMv5 和 ARMv8(64 位)。 |
arm64-v8a | 兼容 ARMv8(64 位),但不兼容 ARMv5 和 ARMv7(32 位)。 |
mips | 仅兼容 MIPS 架构,已过时。 |
mips64 | 仅兼容 MIPS64 架构,已过时。 |
x86 | 兼容 x86 架构,同时兼容 armeabi 和 armeabi-v7a(通过二进制翻译运行)。 |
x86_64 | 兼容 x86_64 架构,同时兼容 arm64-v8a(通过二进制翻译运行)。 |
x86 和 x86_64 的特殊性
x86:主要用于模拟器和部分低端设备。通过二进制翻译,可以运行 armeabi 和 armeabi-v7a 的代码,但性能较低。
x86_64:主要用于模拟器和高性能设备。通过二进制翻译,可以运行 arm64-v8a 的代码。
ABI 配置
在 Android 项目中,可以通过 Gradle 配置支持的 ABI。
android {defaultConfig {ndk {abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'}}
}
小结
ARM 架构:armeabi-v7a 和 arm64-v8a 是当前主流的架构。
x86 架构:主要用于模拟器,通过二进制翻译可以运行 ARM 架构的代码。
ABI 配置:通过 Gradle 的 abiFilters 指定支持的 ABI。
问题
当遇到不能run,编译没错误信息,则进行sync now即可解决

学习资料分享
0voice · GitHub
相关文章:
Android NDK开发入门2之适应idm环境
环境搭建 Android NDK开发实战之环境搭建篇(so库,Gemini ai)-CSDN博客 初始配置 前面已经运行了一个简单的初始程序,现在我们来往初始程序添加类和函数,并成功运行的实验。 一级配置 第一层配置主要是cmake文件环境和一些编译选项。 build配置 可参…...
如何隐藏 Nginx 版本号 并自定义服务器信息,提升安全性
🏡作者主页:点击! Nginx-从零开始的服务器之旅专栏:点击! 🐧Linux高级管理防护和群集专栏:点击!点击!点击! ⏰️创作时间:2025年1月8日8点14分…...
鸿蒙的APP真机调试以及发布
目录: 1、创建好鸿蒙项目2、创建AGC项目3、实现自动签名3.1、手动方式创建签名文件和密码 4、运行项目5、无线真机调试 1、创建好鸿蒙项目 2、创建AGC项目 (1)在File->Project Structure->Project->Signing Configs中进行登录。(未…...
图像处理|膨胀操作
在图像处理领域,形态学操作是一种基于图像形状的操作,用于分析和处理图像中对象的几何结构。**膨胀操作(Dilation)**是形态学操作的一种,它能够扩展图像中白色区域(前景)或减少黑色区域…...
攻防世界 ics-07
点击之后发现有个项目管理能进,点进去,点击看到源码,如下三段 <?php session_start(); if (!isset($_GET[page])) { show_source(__FILE__); die(); } if (isset($_GET[page]) && $_GET[page] ! index.php) { include(flag.php);…...
C# 之某度协议登录,JS逆向,手机号绑定,获取CK
.NET兼职社区 .NET兼职社区 .NET兼职社区 .NET兼职社区 有需要指导,请私信我留言V或者去社区找客服。...
js适配器模式
适配器模式通过把一个类的接口变换成客户端所期待的另一种接口,可以帮我们解决不兼容的问题。 应用 // Ajax适配器函数,入参与旧接口保持一致 async function AjaxAdapter(type, url, data, success, failed) {const type type.toUpperCase()let resul…...
小徐影城管理系统(源码+数据库+文档)
亲测完美运行带论文:文末获取源码 文章目录 项目简介(论文摘要)运行视频包含的文件列表(含论文)前端运行截图后端运行截图 项目简介(论文摘要) 随着现在网络的快速发展,网上管理系统…...
Linux第101步_了解LCD屏驱动“panel-simple.c”
了解LCD屏驱动“panel-simple.c”有助于修改屏驱动。自己另外单独写屏驱动,这是不现实的,所以学会在源程序的基础上修改,才是最佳的学习方法,这就是我们学习框架的主要原因。在Limux系统中,主流的显示框架有两种:DRM(D…...
【实用技能】如何使用 .NET C# 中的 Azure Key Vault 中的 PFX 证书对 PDF 文档进行签名
TX Text Control 是一款功能类似于 MS Word 的文字处理控件,包括文档创建、编辑、打印、邮件合并、格式转换、拆分合并、导入导出、批量生成等功能。广泛应用于企业文档管理,网站内容发布,电子病历中病案模板创建、病历书写、修改历史、连续打…...
前端基础函数算法整理应用(sort+reduce+date+双重for循环)
文章目录 基础函数算法reduce 函数算法sort 函数算法时间排序1. 对日期字符串数组进行排序2. 对包含日期对象的数组进行排序3. 对包含时间戳的数组进行排序4. 对包含日期时间信息的对象数组进行排序 基础函数算法 一、排序算法 冒泡排序(Bubble Sort) …...
鸿蒙MPChart图表自定义(六)在图表中绘制游标
在鸿蒙开发中,MPChart 是一个非常强大的图表库,它可以帮助我们创建各种精美的图表。今天,我们将继续探索鸿蒙MPChart的自定义功能,重点介绍如何在图表中绘制游标。 OpenHarmony三方库中心仓 一、效果演示 以下是效果演示图&…...
poi-tl+kkviewfile实现生成pdf业务报告
需求背景,需要把ai生成的一些业务数据,生成一份pdf报告 需求分析 简单来说,就是json生成pdf的方案。 直接生成pdf。适合一些pdf样式简单的场景,一般就是纯文本按序渲染,或者是纯表格。如果需要一些复杂的排布&#x…...
【Uniapp-Vue3】scroll-view可滚动视图区域组件
如果我们有一个区域有限的大盒子(黑),而我们要在盒子中装的东西(灰)过多,我们就会用到滚动视图: 表现在代码上就是下面这个样子: <template><view class"scrollView&…...
asp.net core webapi中的数据注解与数据验证
在这一课中,主要讲解了如何在 Web API 中使用数据注解(Data Annotations)和进行数据验证,以确保请求数据的有效性和完整性。 在 Web API 中,数据验证是确保客户端传递的数据符合业务规则和格式要求的关键步骤。数据注…...
PixPin—— 高效截图工具的下载与使用攻略
在日常的工作和学习中,一款好用的截图工具能极大地提高我们的效率。今天就来给大家介绍一款功能强大的截图工具 ——PixPin。 下载篇 PixPin 的下载非常简单,只需访问下载网站,在首页就能找到适合你操作系统的下载链接。如果你使用的是 Win…...
Go语言的 的多态性(Polymorphism)基础知识
Go语言的多态性(Polymorphism)基础知识 在编程语言中,多态性是一个核心概念,它允许同一接口被不同的数据类型所实现,从而在不影响代码结构的情况下增强代码的灵活性和可扩展性。在Go语言中,多态性通过接口…...
Vue框架主要用来做什么?Vue框架的好处和特性.
在快速发展的互联网时代,前端开发技术的变革日新月异,为开发者带来了前所未有的机遇与挑战。Vue.js,作为前端开发领域的一颗璀璨新星,以其轻量级、高效灵活的特性,赢得了广大开发者的青睐。本文将深入探讨Vue框架的主要…...
科普CMOS传感器的工作原理及特点
在当今数字化成像的时代,图像传感器无疑是幕后的关键 “功臣”,它宛如一位神奇的 “光影魔法师”,通过光电效应这一奇妙的物理现象,将光子巧妙地转换成电荷,为图像的诞生奠定基础。而在众多类型的图像传感器中…...
tensorflow 内存错误
使用tensorflow训练多个模型时,训练过程中容易出现内存错误,在这里记录一下解决办法。希望能帮到各位。 2025-01-02 22:31:03.489713: W tensorflow/core/common_runtime/bfc_allocator.cc:275] Allocator (GPU_0_bfc) ran out of memory trying to all…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
