Android C/C++ 开发

本文详细介绍如何在Android平台上利用C/C++进行开发,包括配置编译环境、编译独立的C/C++程序及动态库的方法,并探讨了Android NDK的功能限制。

严格意义上来讲,Google Android 平台只支持基于 Android Dalvik VM 的 Java 语言开发,当前的 Android 对C/C++开发的支持仅限于用C/C++开发动态链接库,然后在Java中以JNI的形式来调用,换句话说,仅仅依靠C/C++在Android平台上进行应用的开发,当前还无法实现。这对于广大在Symbian和Windows Phone平台上使用C/C++进行手机应用开发的开发者来说并不是一个好消息。对于Android本身来说,也有不利的地方,它将大量的C/C++开发主力军挡在了Android平台的门外,不利于Android的繁荣发展。

当然,作为一个被广泛装载的智能手机操作系统平台,平台本身对开发的多样性的支持将是一种趋势,类似于占市场主导地位的Symbian支持C++,Java开发。

随着Android NDK的推出,我们也看到了Google 对Android平台下支持C/C++开发所进行的努力,由此,Android平台的C/C++开发也进入了正规军的行列,虽然还不是主力军。尽管当前Google推出了有助于C/C++开发的NDK,但是当前版本的NDK功能上还有很多局限性:NDK并没有提供对应用程序生命周期的维护;NDK也不提供对Android系统中大量系统事件的支持;对于作为应用程序交互接口的UI API,当前版本的NDK中也没有提供,由此可见,NDK只是Google对Android平台上C/C++开发的一个初步的支持,我们期待Google可以做得更多更好。

Android 平台整体架构分为4层,分别为:

Applications:                                                      应用程序层

Application Framework:                           应用程序框架层

Library && Android Runtime:               底层功能库以及Android运行时

Linux Kernel:                                                     Linux 内核

Android 整体架构图如下:

Android 不支持 C/C++ 开发? 虚拟机以上的程序是 JAVA开发,但是底层可以用 C/C++ 跑一些 后台 程序啊, 大不了用 soket 通信嘛. 计划在 rootfs  里存放一套自己的 busybox, 自己的 Bash, 自己的 command 等,command 完全可以做成静态的, Android 里的 shell 实在太难用了。

用 Android.mk 的方式去编译 C 程序也实在是太麻烦, 打算整理出一套 其他的编译 C  程序的方法.NDK? NDK 只是 JNI 的完善,能方便的把 so 和 java 程序打包到 apk 文件中去.很多人说只能静态编译C 程序, 那是胡扯,你如果用 android 里的交叉编译工具,用它 的环境去编译,自然可以不用静态。

下面给出一套方法, 方便的用  Android 环境,编译 C/C++ 程序。

后续,我还会尝试移植各种 C 库到 Android 中去,也会分享一些 移植的经验和方法。

先自己做一个配置文件, 主要是  Android的编译和 链接参数:

cat zconfig.mk


ifdef ANDDROID
Abionic=$(A)bionic/libc/
AoutLib=$(A)out/target/product/generic/obj/lib/
CFLAGS += -I $(A)bionic/libc/arch-arm/include -I $(A)bionic/libc/include -I $(A)bionic/libc/kernel/common -I $(A)bionic/libc/kernel/arch-arm -c -fno-exceptions -Wno-multichar -march=armv5te -mtune=xscale -msoft-float -fpic -mthumb-interwork -ffunction-sections -funwind-tables \
 -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ \
 -include $(A)system/core/include/arch/linux-arm/AndroidConfig.h -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -DSK_RELEASE -DNDEBUG \
 -O2 -Wstrict-aliasing=2 -finline-functions -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop \
 -frename-registers -DNDEBUG -UDEBUG -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64  -MD

LIBS +=-nostdlib -Bdynamic -Wl,-T,$(A)build/core/armelf.x -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc

LIBS +=-L$(AoutLib) -Wl,-rpath-link=$(AoutLib) -lc -lm  $(AoutLib)crtbegin_dynamic.o -Wl,--no-undefined $(A)/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a $(AoutLib)crtend_android.o
endif

接下来是一个通用的 Makefile, 这个 Makefile 中需要包含 zconfig.mk

cat Makefile

ifdef TARGET
include zconfig.mk
CROSS=$(CROSS_COMPILER)-
CC=$(CROSS)gcc
AR=$(CROSS)ar
LD=$(CROSS)ld
else
CC = gcc
AR = ar
LD = ld
STRIP = strip
endif

INCLUDE+= -I../ -I./

OBJ_DIR = obj/
OBJECTS = $(OBJ_DIR)hello.o
TARGET_OUTPUT=./hello

CFLAGS +=
all: $(TARGET_OUTPUT) $(TEST_OUTPUT) $(OBJECTS)

$(OBJ_DIR)%.o: %.c
        @-mkdir -p $(OBJ_DIR)
        $(CC) $(INCLUDE) $(CFLAGS) -c $< -o $@

$(TARGET_OUTPUT): $(OBJECTS)
        $(CC) $(LIBS) -o $(TARGET_OUTPUT) $(OBJECTS) $(LD_PATH) $(LIBOBJECTS)
        @echo "make $@ finished on `date`"
clean:
        @rm -f $(TARGET_OUTPUT)
        @rm -rf obj

然后是一个  hello.c

#include <stdio.h>

int main()
{
        printf("hello world \n");
        return 0;
}

自己的编译环境变量:

cat setenv.sh

export PATH=$PATH:/android/myandroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin
export CROSS_COMPILER=arm-eabi
export TARGET=1
export ANDDROID=1
export A=/android/mydroid/

在 编译 helloworld 以前, 请确认,你已经编译过 android  源代码,

确认 out 目录下有相应的库和工具。

这套机制十分灵活,你可以轻松的编译 X86  版, ARM LINUX 版, Android 版。

最后执行

make

编译成功以后, 用 adb push 把程序放到 虚拟机里。

如果要编译动态库,则有有点小小的差异, 接下来会介绍。

标准的做法是 把 src 放到  /Android/develop/ 目录下去,然后建立 Android.mk 文件,

然后 make modue ...., 但是,这种方式 太麻烦。

下面介绍一种方法,可以比较快速的编译 C 库,

和上一篇中一样,首先要设置自己的环境变量:

cat setenv.sh

export PATH=$PATH:/android/myandroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin
export CROSS_COMPILER=arm-eabi
export TARGET=1
export ANDDROID=1
export A=/android/mydroid/

然后依然是建立一个 mk 文件:

cat zconfiglib.mk


ifdef ANDDROID
Abionic=$(A)bionic/libc/
AoutLib=$(A)out/target/product/teton_ebook/obj/lib/
CFLAGS += -I $(A)bionic/libc/arch-arm/include -I $(A)bionic/libc/include -I $(A)bionic/libc/kernel/common -I $(A)bionic/libc/kernel/arch-arm -c -fno-exceptions -Wno-multichar -march=armv5te -mtune=xscale -msoft-float -fpic -mthumb-interwork -ffunction-sections -funwind-tables \
 -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ \
 -include $(A)system/core/include/arch/linux-arm/AndroidConfig.h -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -DSK_RELEASE -DNDEBUG \
 -O2 -Wstrict-aliasing=2 -finline-functions -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop \
 -frename-registers -DNDEBUG -UDEBUG -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64  -MD

LIBS += -nostdlib -Wl,-soname, -Wl,-T,$(A)build/core/armelf.xsc -Wl,--gc-sections -Wl,-Bsymbolic -L$(AoutLib) -Wl,--whole-archive   -Wl,--no-whole-archive -lc  -lm -Wl,--no-undefined   $(A)/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/interwork/libgcc.a

然后是你自己的 lib 的 makefile.

cat makefile


ifdef TARGET
include /zconfiglib.mk
CROSS=$(CROSS_COMPILER)-
CC=$(CROSS)gcc
AR=$(CROSS)ar
LD=$(CROSS)ld
else
CC = gcc
AR = ar
LD = ld
STRIP = strip
endif

INCLUDE+= -I../ -I./

LIBS+= -shared

OBJ_DIR = obj/
OBJECTS = $(OBJ_DIR)hello.o
TARGET_OUTPUT=./libhello

CFLAGS +=
all: $(TARGET_OUTPUT) $(TEST_OUTPUT) $(OBJECTS)

$(OBJ_DIR)%.o: %.c
        @-mkdir -p $(OBJ_DIR)
        $(CC) $(INCLUDE) $(CFLAGS) -c $< -o $@

$(TARGET_OUTPUT): $(OBJECTS)
        $(CC) $(LIBS) -o $(TARGET_OUTPUT) $(OBJECTS) $(LD_PATH)
        @echo "make $@ finished on `date`"
clean:
        @rm -f $(TARGET_OUTPUT)
        @rm -rf obj

然后  make 就可以了。


编译出来的库貌似需要放到  /system/lib 下去。

<think>首先,用户的问题是:“我想在Android平台上进行C/C++开发 请问Android C/C++ 开发指南和环境配置”。这涉及到Android平台上的原生开发,使用C/C++语言。 系统级指令要求: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户可见层要求: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考站内引用: - 引用[1]: 关于JNI框架,用于Java和C/C++交互。 - 引用[2]: 关于Android C/C++开发使用NDK和JNI。 这些引用是关于JNI和NDK的,与用户的问题相关。用户的问题是关于Android C/C++开发的环境配置和指南,所以我应该整合这些信息。 结构化回答: - 我需要提供一个清晰的指南,从环境配置开始。 - 步骤包括:安装工具、配置项目、编写代码、编译和运行。 - 参考引用:在适当的地方添加引用标识。 关键点基于引用: - 引用[2]提到:使用NDK进行C/C++开发,JNI用于Java和C/C++交互。 - 引用[1]提到:JNI框架的重要性,以及环境配置如JDK和NDK的安装。 所以,回答应该包括: 1. **环境配置**:安装JDK和NDK。 2. **NDK介绍**:什么是NDK,如何用于C/C++开发。 3. **JNI介绍**:如何通过JNI与Java交互。 4. **项目设置**:在Android Studio中配置NDK。 5. **示例代码**:提供一个简单的C/C++代码示例。 6. **编译和运行**:如何构建和测试。 生成相关问题:在回答末尾,添加相关问题,如示例中的“§§相关问题§§”。 确保中文回答。 现在,构建回答结构: - **引言**:简要介绍Android C/C++开发。 - **步骤1:环境配置**:安装JDK和NDK。 - **步骤2:配置Android Studio**:设置NDK路径。 - **步骤3:创建项目**:在Android Studio中创建新项目并添加C/C++支持。 - **步骤4:编写代码**:示例JNI代码。 - **步骤5:编译和运行**:构建APK并测试。 - **相关问题**:生成几个相关问题。 添加引用:在描述JDK和NDK安装时,引用[1];在描述NDK和JNI时,引用[2]。 数学表达式:用户的问题不涉及数学,但如果需要,我可以添加一些,比如在解释性能时,但可能不需要。系统指令说“所有行内数学表达式”,但在这个上下文中,可能不适用。我可以避免或只在必要时添加。 最终输出格式: - 使用Markdown。 - 代码块用```包裹。 - 引用标识如[^1]。 相关问题想法: 1. 如何优化C/C++代码在Android上的性能? 2. JNI的最佳实践有哪些? 3. 如何处理Android中的内存管理? 4. 有哪些常见的NDK开发错误和解决方案?</think>以下是针对您的查询“Android C/C++ 开发指南和环境配置”的完整解答。我将基于Android原生开发的核心工具——NDK(Native Development Kit)和JNI(Java Native Interface)——提供结构化指南。这些工具允许您在Android应用中集成高性能的C/C++代码,并通过JNI实现与Java/Kotlin的交互[^2]。指南分为环境配置、项目设置、代码示例和编译运行等步骤,确保您能逐步上手。内容参考了Android官方文档和相关实践[^1][^2],力求真实可靠。 ### 1. 环境配置 Android C/C++开发依赖于JDK(Java Development Kit)和NDK。以下是基本要求: - **JDK安装**:用于编译Java/Kotlin代码。推荐使用OpenJDK 11或更高版本。从[Oracle官网](https://www.oracle.com/java/technologies/downloads/)或[Adoptium](https://adoptium.net/)下载并安装,设置`JAVA_HOME`环境变量指向安装路径[^1]。 - **NDK安装**:用于编译C/C++代码。在Android Studio中安装: 1. 打开Android Studio(推荐版本2023.2.1+)。 2. 进入“Tools” > “SDK Manager” > “SDK Tools”选项卡。 3. 勾选“NDK (Side by side)”和“CMake”(用于构建C/C++项目),点击“Apply”安装。 4. 安装后,设置`ANDROID_NDK_HOME`环境变量(例如:`C:\Users\YourName\AppData\Local\Android\Sdk\ndk\25.2.9519653`)。 验证安装:在终端运行`ndk-build --version`,应输出NDK版本号[^1][^2]。 ### 2. 配置Android Studio项目 在Android Studio中创建支持C/C++的项目: 1. **新建项目**:选择“File” > “New” > “New Project”,在模板中选择“Native C++”。这将自动生成包含JNI接口的基本项目。 2. **配置CMake**:项目创建时,Android Studio会生成`CMakeLists.txt`文件(用于定义C/C++编译规则)。确保`build.gradle`文件中包含NDK配置: ```gradle android { defaultConfig { externalNativeBuild { cmake { cppFlags "-std=c++17" // 使用C++17标准 } } ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' // 指定目标CPU架构 } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" // CMake文件路径 } } } ``` 3. **添加C/C++源文件**:在`app/src/main/cpp/`目录下创建`.cpp`或`.c`文件。例如,创建`native-lib.cpp`。 ### 3. 编写C/C++代码与JNI接口 JNI允许Java调用C/C++函数。以下是一个简单示例: - **Java端代码**:在MainActivity中声明native方法。 ```java public class MainActivity extends AppCompatActivity { static { System.loadLibrary("native-lib"); // 加载编译后的C++库 } public native String stringFromJNI(); // 声明native方法 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = findViewById(R.id.sample_text); tv.setText(stringFromJNI()); // 调用C++函数 } } ``` - **C++端代码**:在`native-lib.cpp`中实现函数。 ```cpp #include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_example_myapp_MainActivity_stringFromJNI(JNIEnv* env, jobject /* this */) { std::string hello = "Hello from C++!"; return env->NewStringUTF(hello.c_str()); } ``` 注意:函数名必须遵循JNI命名规范(如`Java_包名_类名_方法名`)[^2]。 ### 4. 编译和运行 - **构建项目**:点击Android Studio的“Build” > “Make Project”。CMake会自动编译C/C++代码为共享库(如`libnative-lib.so`)。 - **运行测试**:连接Android设备或使用模拟器,点击“Run”按钮。应用将显示“Hello from C++!”文本,验证JNI调用成功。 - **调试**:使用LLDB调试器(Android Studio内置)设置断点。在“Run” > “Edit Configurations”中启用“Debug native code”。 ### 关键注意事项 - **性能优化**:C/C++代码适合计算密集型任务(如游戏物理引擎$F = ma$或图像处理)。但需注意内存管理,避免JNI引用泄漏[^1]。 - **兼容性**:NDK支持C++17标准,确保代码在不同Android版本(最低API 21+)运行。 - **资源参考**:官方文档[Android NDK指南](https://developer.android.com/ndk/guides)和[JNI规范](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/)是权威来源[^2]。 通过以上步骤,您可以在Android平台上高效开发C/C++应用。JNI框架是实现Java和C/C++交互的核心,它结合了Java的跨平台性和C/C++的高性能[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值