使用NDK编译C/C++文件生成在安卓中的可执行文件

需求:

要编译一个C文件,然后将他运行到安卓手机中,通过这个可执行文件可以获取一些硬件的参数信息,或者对已经有的信息进行修改,从而达到我们想要的效果

相关知识点记录:

  1. NDK:Native Development Kit,是 Android 的一个工具开发包。NDK 可以看做是 Android 中实现 JNI 的一种手段,通过 NDK,还可以打包 C/C++ 动态库,并自动打包进 APK/AAR 中。我们可以到安卓官网下载NDK,可以直接执行NDK命令,也可以集成NDK到AndroidStudio中编译C/C++文件。

  2. JNI:Java Native Interface,即 Java 本地接口。使得 Java 与本地其他类型语言(如 C、C++)交互。也就是在 Java 中调用 C/C++ 代码,或者在 C/C++ 中调用 Java 代码。JNI 是 Java 的,和 Android 无关。

  3. .SO文件:so文件是Linux下的程序函数库,即编译好的可以供其他程序使用的代码和数据。一般来说.so文件就是常说的动态链接库, 都是C或C++编译出来的。与Java比较就是:它通常是用的Class文件(字节码)。Linux下的.so文件时不能直接运行的,一般来讲,.so文件称为共享库。

  4. Android.mk :文件位于项目 jni/ 目录的子目录中,用于向编译系统描述源文件和共享库。它实际上是编译系统解析一次或多次的微小 GNU makefile 片段。Android.mk 文件用于定义 Application.mk、编译系统和环境变量所未定义的项目范围设置。它还可替换特定模块的项目范围设置。Android.mk 的语法支持将源文件分组为模块。模块是静态库、共享库或独立的可执行文件。

使用最原始的方法编译C/C++文件

1,创建.c/.cpp文件,我们拿我们拿我们自己已经有的文件当例子(ilitek_TDDI.c文件),建议创建一个单独的文件夹用来编译执行ndk命令。我们存放在D:/DEMO临时文件夹下面。

2,新建两个文件Android.mk和Application.mk,然后分别按照如下代码对Android.mk文件和Application.mk文件进行编辑。

#Adroid.mk文件内容

LOCAL_PATH := $(call my-dir) 
include $(CLEAR_VARS)          #会清理除了LOCAL_PATH歪的其他LOCAL文件路径
LOCAL_CFLAGS += -std=c99       #使用c语言c99规范
LOCAL_CFLAGS += -pie -fPIE     #相当于在源文件中增加宏定义,安卓5.0以上需要添加,否则编译出来无法使用
LOCAL_LDFLAGS += -pie -fPIE    #相当于在源文件中增加宏定义,安卓5.0以上需要添加,否则编译出来无法使用
LOCAL_ARM_MODE := arm          #模块指令集
LOCAL_MODULE    := TestNdk     #模块名称(最后生成的可执行文件的名字,可以按照需求修改)
LOCAL_SRC_FILES := TestNdk.c   #源文件名(需要替换成我们自己的.c文件)
include $(BUILD_EXECUTABLE)    #编译为可执行文件
#Application.mk文件内容

APP_ABI := x86 armeabi-v8a
APP_ABI是指明编译与调试的CPU架构。
目前Android系统支持以下七种不同的CPU架构:ARMv5,ARMv7(从2010年起),x86(从2011年),MIPS(从2012年),ARMv8,MIPS64和x86_64(从2014年),每一种都对应相应的ABI。相应生成arm64-v8a,mips64,x86_64下的文件需要NDK_r10以上版本支持。在Application.mk文件里配置APP_ABI的内容。
根据不同的NDK版本,APP_ABI := all仅能生成当前版本支持的ABI信息库文件,如果需要生成最新的必须更新相应的NDK版本。
或者明确写明支持的CPU架构APP_ABI := armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64
注意:由于目前版本支持的问题,采用Eclipse+NDK+Windows集成方式开发,对应编译生成对应CPU架构的so文件是没有问题的。但是不一定可以执行调试工作,启动NDK调试模式时将会提示无法识别对应的ABI。
注意:

(1)、目前模拟器只有x86_64的没有arm64-v8a的;
(2)、在用真机测试armv8-a时,最好先通过adb shell, cat /proc/cpuinfo ,来查看下真机是否是支持armv8-a;
(3)、arm32和arm64有些配置参数不能共存,如-msoft-float仅在arm32位下支持,在arm64位下是不支持的.

3,打开CMD切换到NDK解压路径下面(含有ndk-build.cmd等文件的目录),在这个目录下面可以使用命令ndk-build。也可以通过配置环境变量的方式,这样可以在任何路径下面执行ndk-build命令,配置环境变量的过程此处不再赘述。

4,在CMD窗口下面输入下面的命令。

ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk

# ndk-build是执行命令的关键字
# NDK_PROJECT_PATH是你的工程存放的路径,比如我放在了D盘的DEMO文件夹下面,就是D:/DEMO
#APP_BUILD_SCRIPT是你的Android.mk文件存放的地方。一般情况下我们都会将工程文件和mk文件存放在一起,所以路径和上述路径一致,在后面加上Android.mk即可。

5,点击回车后执行,会发现在我们的工程路径下面会多出来两个文件夹,一个是libs,另一个是obj。

6,其中libs文件夹下面会按照不同的架构生成不同的文件夹,根据我们的设备的实际情况,找到合适的文件夹打开,可以找到可执行文件(TestNDK),这个文件的名字是我们在Android.mk文件下面定义好的。

7,然后我们就可以将这个文件push到设备上面,执行我们定义好的内容。

在这里插入图片描述

下面是通过程序获取info信息的脚本文件内容

adb push TestNdk /data/local/tmp                   #将文件TestNdk推送到/data/local/tmp目录下
adb shell chmod 777 /data/local/tmp/TestNdk		   #修改文件TestNdk的权限为777
adb shell ./data/local/tmp/TestNdk				  #执行文件TestNdk

#可以以此执行以下代码查看文件是否发送成功。
#adb shell
#su
#cd /data/local/tmp
#ls

将以上内容保存到bat格式的文件中,然后pc连接设备,将上述脚本文件和已经编译好要执行的文件,复制到adb所在文件夹下,双击bat文件执行。就可以在命令窗口得到相关的设备信息。

如果在执行之后发现cmd命令框输出的结果是乱码,原因是由于CMD控制台所使用的代码页和TestNdk的代码页不匹配导致的,TestNdk使用的是UTF-8编码,而CMD控制台默认使用的GBK编码。

修改CMD窗口的默认代码页为UTF-8编码即可,我们新建一个CMD窗口,输入命令chcp 65001,意思是修改CMD的代码页为65001,65001就是UTF-8编码
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐