在 Android App 里使用 C 代码 - NDK

原生开发套件 (NDK) 是一套工具,使能够在 Android 应用中使用 C 和 C++ 代码,并提供众多平台库,可使用这些平台库管理原生 activity 和访问实体设备组件,例如传感器和触控输入。

NDK 可能不适合大多数 Android 编程初学者,这些初学者只需使用 Java 代码和框架 API 开发应用。

如果需要实现下列目标,NDK 就能派上用场:

  • 进一步提升设备性能,以降低延迟或运行游戏或物理模拟等计算密集型应用。
  • 重复使用自己或其他开发者的 C 或 C++ 库。

开发者可以在 Android Studio 2.2 或更高版本中使用 NDK 将 C 和 C++ 代码编译到原生库中,然后使用 Android Studio 的集成构建系统 Gradle 将原生库打包到 APK 中。Java 代码随后可以通过 Java 原生接口 (JNI) 框架调用原生库中的函数。

Android Studio 编译原生库的默认构建工具是 CMake。由于很多现有项目都使用 ndk-build 构建工具包,因此 Android Studio 也支持 ndk-build。如果创建新的原生库,则应使用 CMake。

一、基本流程操作:

Android Studio 设置完成后,可以直接创建支持 C/C++ 的新项目。但如果需要向现有 Android Studio 项目添加或导入原生代码,可以按以下基本流程操作:

  1. 编写 C 代码:首先,你需要编写 C 代码,并将其编译成适用于 Android 平台的共享库(.so 文件)。这通常需要使用 Android NDK(Native Development Kit),它提供了用于编译本地代码的工具链。

  2. 创建 Android 项目:接下来,需要创建一个 Android 项目,用于包装你的 C 代码和 Java/Kotlin 代码。这个项目可以使用 Android Studio 来创建和管理。

  3. 集成本地库:在 Android 项目中,需要将编译好的 .so 文件放置在正确的位置,通常是在 app/src/main/jniLibs/<ABI>/ 目录下,其中 <ABI> 是目标设备的 ABI(如 armeabi-v7a, arm64-v8a, x86, x86_64 等)。这样,Android 运行时就能找到并加载这些本地库。

  4. 使用 JNI 调用 C 函数:在 Java 或 Kotlin 代码中,可以使用 JNI(Java Native Interface)来调用 C 函数。需要声明本地方法,并在 C 代码中实现这些方法的逻辑。JNI 允许 Java/Kotlin 代码与本地代码进行交互。

  5. 构建和测试:最后,构建你的 Android 应用,并在目标设备上进行测试。确保你的 C 代码能够正确执行,并且与 Java/Kotlin 代码之间的交互没有问题。

二、示例代码:

Android 提供了 Java Native Interface (JNI) 来调用 native 代码(如 C/C++)。下面是一个简单的示例,帮你了解如何在 Android App 里调用 C 代码。

C 代码 (fir.c)

#include <stdio.h>void fir(int* input, int* output, int length) {for (int i = 0; i < length; i++) {output[i] = input[i] * 2; // 一个简单的 FIR 滤波器}
}

这个 C 代码定义了一个 fir 函数,它将输入数组乘以 2,并将结果存储在输出数组中。

JNI 头文件 (fir.h)

#ifndef FIR_H
#define FIR_H#ifdef __cplusplus
extern "C" {
#endifvoid Java_MainActivity_fir(JNIEnv* env, jobject thiz, jintArray input, jintArray output, jint length);#ifdef __cplusplus
}
#endif#endif  // FIR_H

这个头文件定义了一个 JNI 函数 Java_MainActivity_fir,它将被 Java 代码调用。该函数将输入数组、输出数组和长度作为参数。

JNI 实现文件 (fir.cpp)

#include "fir.h"
#include "jni.h"void Java_MainActivity_fir(JNIEnv* env, jobject thiz, jintArray input, jintArray output, jint length) {// 获取输入数组的指针jint* input_ptr = env->GetIntArrayElements(input, NULL);// 获取输出数组的指针jint* output_ptr = env->GetIntArrayElements(output, NULL);// 调用 C 函数fir(input_ptr, output_ptr, length);// 释放数组指针env->ReleaseIntArrayElements(input, input_ptr, 0);env->ReleaseIntArrayElements(output, output_ptr, 0);
}

这个文件实现了 JNI 函数 Java_MainActivity_fir。它获取输入数组和输出数组的指针,调用 C 函数 fir,并释放数组指针。

Android 项目结构

  • jni 目录:包含 C 代码和 JNI 头文件
    • fir.c
    • fir.h
    • fir.cpp
  • java 目录:包含 Java 代码
    • MainActivity.java

Java 代码 (MainActivity.java)

public class MainActivity extends AppCompatActivity {// 加载 native 库static {System.loadLibrary("fir");}// 声明 native 方法public native void fir(int[] input, int[] output, int length);@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 创建输入数组int[] input = new int[] {1, 2, 3, 4, 5};// 创建输出数组int[] output = new int[input.length];// 调用 native 方法fir(input, output, input.length);// 打印输出结果for (int i = 0; i < output.length; i++) {Log.d("MainActivity", "output[" + i + "] = " + output[i]);}}
}

这个 Java 代码加载 native 库,声明 native 方法 fir,并在 onCreate 方法中调用该方法。

Android.mk 文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)LOCAL_MODULE    := fir
LOCAL_SRC_FILES := fir.cpp
LOCAL_LDLIBS    := -lloginclude $(BUILD_SHARED_LIBRARY)

这个文件告诉 Android NDK 如何编译 native 库。

三、编译和运行:

  1. 在 Android 项目目录下创建 jni 目录,并将 C 代码和 JNI 头文件添加到该目录下。
  2. jni 目录下创建 Android.mk 文件,并添加编译指令。
  3. 使用 Android NDK 编译 native 库:ndk-build NDK_DEBUG=1
  4. 在 Java 代码中加载 native 库,并调用 native 方法。
  5. 运行 Android App,并查看输出结果。

输出结果应该是:

D/MainActivity: output[0] = 2
D/MainActivity: output[1] = 4
D/MainActivity: output[2] = 6
D/MainActivity: output[3] = 8
D/MainActivity: output[4] = 10

小结:

上述是基本的概念流程,如果想自己试一试,可以以此Hello JNI代码为例,增加输入和显示等,修改算法,构建一个在手机运行的 app,我做了一个简单的 app,截图如下:

                                                                                         老徐,端午,2024/6/10

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/851286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

追觅科技2025校园招聘测评已发(真题)

&#x1f4e3;追觅科技 2025校园招聘测评已发&#xff0c;正在申请的小伙伴看过来哦&#x1f440; ㊙本次校招面向全球于2023年7月 - 2025年12月期间毕业的同学&#xff0c;开放了四大类岗位&#xff1a;营销类、研发类、制作供应类、职能类~ ✅测评解析 &#x1f449; 测评自…

git的核心概念(合作开发时必须了解)

Git是我们管理项目的重要工作&#xff0c;它有几个核心概念&#xff0c;核心概念之间又有相关操作&#xff0c;在开发前应该学会。 4个概念&#xff1a;工作区、暂存区、本地仓库、远程仓库。 工作区&#xff1a;你的工作目录&#xff0c;可能是项目目录。 操作&#xff1a; …

芒果YOLOv10改进38:写作篇:一文了解YOLOv10如何打印FPS指标

只需订阅这一个专栏即可阅读:芒果YOLOv10所有改进内容 💡🚀🚀🚀本博客内含改进源代码,按步骤操作运行改进后的代码即可 💡更方便的统计更多实验数据,方便写作 新增YOLOv10打印FPS指标 完善(一键YOLOv10打印FPS指标) 文章目录 完善(一键YOLOv10打印FPS指标)YOLO…

Linux系统编程(十一)线程、线程控制

线程 一、线程概念&#xff1a; ps -eLf 查看线程号&#xff08;cpu 执行的最小单位&#xff09; 二、Linux内核线程实现原理 三、三级映射&#xff08;三级页表&#xff09; 进程PCB-->页面&#xff08;可看成数组&#xff0c;首地址位于PCB中&#xff09;--》页表--》页…

计算机系统基础笔记(10)——浮点数

前言 结合第四篇观看 效果更好^^ 数值型分为两类 定点数 整数小数 浮点数 注意&#xff1a;小数点不用占用二进制位 第一部分 编码 1.小数的二进制表示 位置计数法&#xff1a;小数点左边的权重是正指数&#xff0c;右边的数是负指数&#xff0c;如图 由此可知&#xff0…

贪心算法例子

贪心算法概述 贪心算法是一种在每一步选择中都做出局部最优选择的算法,以期望通过一系列局部最优选择达到全局最优。贪心算法在许多优化问题中表现良好,特别是在某些特定类型的问题中能够保证找到最优解。 活动选择问题(Activity Selection Problem)背包问题(贪心解法)霍…

MySQL数据库(二)和java复习

一.MySQL数据库学习(二) (一).DQL查询数据 DQL&#xff08;Data Query Language&#xff09;是用于从数据库中检索数据的语言。常见的 DQL 语句包括 SELECT、FROM、WHERE、GROUP BY、HAVING 和 ORDER BY 等关键字&#xff0c;用于指定要检索的数据、数据源、过滤条件、分组方…

格式化后硬盘数据能恢复吗?硬盘数据恢复这样做!

硬盘是电脑中必备的数据存储设备&#xff0c;另外还有移动硬盘。移动硬盘存储空间非常大、性价比高、便于携带&#xff0c;给我们带来和很多便利。但是和其他存储设备一样&#xff0c;各种硬盘也会出现各种问题&#xff0c;比如常见的格式化硬盘导致数据丢失的问题。 怎么样恢复…

【软考的系统分析师的考题考点解析2025】

2024-2025系统分析师考试&#xff08;简称软考&#xff09;是计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试中的高级资格考试&#xff0c;主要考察考生在系统分析、系统设计、项目管理等方面的知识和技能。以下是软考系统分析师的常见考点、考题和重点&#x…

【源码】Spring Data JPA原理解析之事务执行原理

Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查询、部分字段查询 3、Spring Data JPA数据批量插入、批量更新真的用对了吗 4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作 5、Spring Data JPA自定…

Python 虚拟环境 + 嵌入式 部署方案

Python 虚拟环境 嵌入式 部署方案 开发阶段1. 在虚拟环境下开发 Python 项目 部署阶段1. 创建项目文件夹2. 准备嵌入器 Python 解释器3. 处理第三方库4. 修改 ._pth 文件添加 Python 运行环境 5. 添加启动 bat 脚本最终目录结构参考资料 开发阶段 1. 在虚拟环境下开发 Python…

PHP 寿光蔬菜大棚宣传平台-计算机毕业设计源码88288

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于寿光蔬菜大棚宣传平台当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了寿光蔬菜大棚宣传平台&#xff0c;它彻底…

ISO 19115-2:2019 附录C XML 模式实现

C.1 XML 模式 本文件中定义的 UML 模型的 XML 模式在 ISO/TS 19115-3 中定义的适当 XML 命名空间中提供。新增内容包括: 命名空间前缀模式文件名Metadata for ACquisition (mac)acquisitionInformationImagery.xsdMetadata for Resource Content (mrc)contentInformationImag…

BPF:BCC(BPF Compiler Collection)工具集认知

写在前面 博文内容为 《BPF Performance Tools》 读书笔记整理内容涉及 BCC 工具整体介绍理解不足小伙伴帮忙指正 &#x1f603;,生活加油 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#xff0c;眼前的风景已经和从前不一样了。——村…

内存EDAC在AMD异构场景的应用

在异构系统中&#xff0c;AMD通过将CPU与GPU的数据织物网络通过定制的xGMI链接连接&#xff0c;实现了统一访问&#xff0c;使得GPU节点的数据织物网络如同CPU节点一样可访问。这样的设计使得系统能够高效地整合CPU与GPU资源&#xff0c;提升数据处理速度和效率&#xff0c;特别…

从河流到空气,BL340工控机助力全面环保监测网络构建

在环保监测领域&#xff0c;智能化、高效率的监测手段正逐步成为守护绿水青山的新常态。其中&#xff0c;ARMxy工业计算机BL340凭借其强大的处理能力、高度的灵活性以及广泛的兼容性&#xff0c;在水质监测站、空气质量检测、噪音污染监控等多个环保应用场景中脱颖而出&#xf…

MySQL深分页优化

MySQL中的深分页问题通常是指当我们通过LIMIT语句查询数据&#xff0c;尤其是在翻到较后面的页码时&#xff0c;性能会急剧下降。例如&#xff0c;查询第1000页的数据&#xff0c;每页10条&#xff0c;系统需要跳过前9990条数据&#xff0c;然后才能获取到所需的记录&#xff0…

Vue基础面试题(一)

1.Vue的基本原理 Vue.js的核心原理在于其响应式的数据绑定机制&#xff0c;当创建一个Vue实例时&#xff0c;Vue会遍历每个属性&#xff0c;用Object.defineProperty转化为getter和setter。这样使得Vue可以追踪属性的变化&#xff0c;在属性被修改和访问时通知变化。每个组件也…

PostgreSQL的视图pg_tables

PostgreSQL的视图pg_tables pg_tables 是 PostgreSQL 中的一个系统视图&#xff0c;用于显示当前数据库中所有用户定义的表的信息。这个视图提供了关于表的名称、所属模式&#xff08;schema&#xff09;、所有者以及表类型等详细信息。 pg_tables 视图的主要列 列名类型描述…

如何提高个人和企业的网络安全意识?

提高个人网络安全意识 个人可以通过以下方式提高网络安全意识&#xff1a; 1. 加强教育和培训&#xff1a;参加网络安全培训课程&#xff0c;学习识别网络攻击的常见迹象、安全密码的设置、不点击可疑链接等知识。 2. 建立网络安全政策&#xff1a;制定个人网络安全规则&…