C++在移动开发中的应用:Android NDK、Unity和Unreal Engine

作者: IT Sectr 发布日期: 2026-02-10 阅读时间: 11 分钟

C++ — 一种多范式编程语言,具有手动内存管理功能,结合了过程式、面向对象和泛型编程。在移动开发中,C++通过Android NDK用于移植库,并通过Unity和Unreal Engine游戏引擎用于创建跨平台游戏。根据TIOBE(2026年),C++在专业开发人员中的受欢迎程度位居前五名。

要点

  • C++ — 一种系统编程语言,用于Android NDK、Unity和Unreal Engine
  • Android NDK 允许将C++代码编译为ARM处理器的原生.so库
  • Unreal Engine 完全基于C++构建,而Unity使用C++进行低级插件开发
  • JNI(Java Native Interface) — Android上Java/Kotlin与C++之间的桥梁
  • CMake和NDK Build — 移动平台上C++项目的构建系统

什么是C++?

C++ — 由Bjarne Stroustrup于1985年创建的编程语言,作为C语言的扩展,增加了对类的支持。C++通过指针提供直接内存访问、模板元编程和多继承。C++17和C++20标准添加了协程、概念和范围。

与Java和Kotlin不同,C++没有垃圾回收器——开发人员通过new和delete运算符手动管理内存的分配和释放。这提供了对性能的完全控制,但需要自律。根据JetBrains Developer Survey(2025),42%的C++开发人员在游戏行业使用该语言。

C++标准每三年进化一次:C++11(lambda、auto、unique_ptr)、C++14(泛型lambda)、C++17(if constexpr、filesystem)、C++20(模块、协程、概念)。Clang和GCC编译器支持所有当前标准,而Android NDK使用LLVM工具链中的Clang。

C++与Java和Kotlin的区别

C++与JVM语言的主要区别——手动内存管理和直接编译为机器码。Java和Kotlin在带有自动垃圾回收器的虚拟机上运行。C++代码被编译为针对特定架构(ARM、x86或RISC-V)的原生二进制文件。

标准C++Java / Kotlin
内存管理手动(new/delete, RAII)自动(Garbage Collector)
编译原生机器码JVM / ART 字节码
性能最大(零成本抽象)高,有GC暂停
在移动开发中的使用NDK、游戏、库UI应用、业务逻辑
构建CMake、NDK Build、Gradle + NDKGradle、Maven
跨平台性为每个平台编译JVM / ART 无处不在

C++在移动开发中的应用:Android NDK

Android NDK(Native Development Kit) — Google的用于用C和C++编写Android应用程序部分的工具集。NDK包括基于Clang的工具链、Android系统头文件、用于调试和分析的库。r27(2025)版本支持C++20并使用LLVM 18。

NDK将C++代码编译为ARM64、ARM32、x86和x86_64架构的动态.so库。Java或Kotlin应用程序通过System.loadLibrary()加载这些库,并通过JNI调用原生函数。根据Google的数据,NDK已被下载超过500万次。

使用NDK的项目结构

一个典型的Android NDK项目包含app/src/main/cpp/文件夹(包含C++源文件)、用于构建的CMakeLists.txt和声明原生方法的Java类。Gradle通过build.gradle中的externalNativeBuild块连接NDK。

cpp
// native-lib.cpp — 一个简单的Android JNI方法
#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_stringFromJNI(
    JNIEnv *env,
    jobject /*thiz*/) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

代码声明了一个全名为Java_com_example_app_MainActivity_stringFromJNI的JNI函数——这是JNI命名约定。该函数接收一个指向JNIEnv(执行环境)的指针和jobject(调用类的实例)。env->NewStringUTF从C++字符串创建Java字符串。

ABI和目标架构

Android支持多个ABI(Application Binary Interface):arm64-v8a(64位ARM设备,99%的现代智能手机)、armeabi-v7a(32位ARM,旧设备)、x86_64(模拟器)。NDK允许通过build.gradle中的ABI过滤器为每个架构构建.so。

gradle
android {
    defaultConfig {
        ndk {
            abiFilters "arm64-v8a", "armeabi-v7a"
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.22.1"
        }
    }
}

C++和游戏引擎:Unity和Unreal Engine

C++ — 游戏引擎的主要语言。Unreal Engine使用C++编写所有游戏代码,而Unity在引擎核心中使用C++进行渲染和物理计算。即使开发人员在Unity中用C#编写代码,幕后C++管理图形、声音和物理计算。

Unreal Engine:C++作为主要语言

Unreal Engine从头开始基于C++构建。游戏逻辑代码使用UHT(Unreal Header Tool)宏编写,以便与Blueprints(可视化脚本系统)集成。类继承自基类型AActor、UObject、UGameInstance,带有前缀字母U、A、F。

cpp
// Unreal Engine中用C++编写的角色类
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"

UCLASS()
class AMyCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    AMyCharacter();

    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;

    UPROPERTY(EditAnywhere, Category = "Movement")
    float MoveSpeed = 600.0f;

protected:
    void SetupPlayerInputComponent(UInputComponent *PlayerInputComponent) override;
};

UCLASS()和UPROPERTY()宏——Unreal Engine反射系统的一部分。UHT(Unreal Header Tool)从头文件生成C++代码,用于序列化、蓝图和网络复制。MoveSpeed通过UPROPERTY(EditAnywhere)在编辑器中显示。

Unity:在插件和Native SDK中使用C++

Unity使用C#编写游戏逻辑,但C++用于Native Plugins——Android的.so库和iOS的.bundle库。通过Android NDK可以连接广告网络的C++ SDK、分析工具,或从桌面游戏移植C++库。

csharp
using System.Runtime.InteropServices;
using UnityEngine;

public class NativeBridge : MonoBehaviour
{
    const string LIB_NAME = "native_plugin";

    [DllImport(LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
    private static extern int ProcessFrame(
        int width, int height,
        IntPtr pixelData
    );

    void Update()
    {
        int result = ProcessFrame(Screen.width, Screen.height, IntPtr.Zero);
        Debug.Log("Frame processed: " + result);
    }
}

在此示例中,C#通过P/Invoke封送对C++函数ProcessFrame的调用。DllImport属性指定.so库的名称。C++函数实时处理帧并返回结果。这种方法用于后期效果和计算机视觉。

JNI:Java与C++的交互

JNI(Java Native Interface) — 从Java或Kotlin调用C/C++代码的标准机制。在Android中,JNI是在ART虚拟机和原生库之间传输数据的唯一方式。每次JNI调用都有开销,因此数据以批处理方式传输,而不是逐个字段。

JNIEnv — 指向JNI函数表的指针。env->FindClass加载Java类,env->GetMethodID获取方法标识符,env->CallVoidMethod调用它。对于字符串,使用GetStringUTFChars和ReleaseStringUTFChars。JNI还支持对Java对象的全局和弱引用。

cpp
// 通过JNI将字节数组从C++传递到Java
extern "C" JNIEXPORT void JNICALL
Java_com_example_app_ImageProcessor_processArray(
    JNIEnv *env, jobject /*thiz*/,
    jbyteArray input, jint length) {

    jbyte *buffer = env->GetByteArrayElements(input, nullptr);
    jsize size = env->GetArrayLength(input);

    for (jsize i = 0; i < size; ++i) {
        buffer[i] = buffer[i] ^ 0xFF; // 反转字节
    }

    env->ReleaseByteArrayElements(input, buffer, JNI_COMMIT);
}

GetByteArrayElements获取指向Java字节数组的指针。ReleaseByteArrayElements中的JNI_COMMIT将更改复制回Java数组而不释放内存。for循环处理在CPU上以最大C++性能执行,没有GC暂停。

JNI中的内存管理

JNI的主要危险——全局引用泄漏。每个NewGlobalRef必须通过DeleteGlobalRef释放。局部引用(由FindClass、NewStringUTF返回)在从原生函数返回时自动删除。对于密集型调用,请使用PushLocalFrame / PopLocalFrame。

CMake和Android上C++的构建系统

CMake — Android NDK中C++的主要构建工具。CMakeLists.txt描述构建目标、库和依赖关系。Gradle通过externalNativeBuild调用CMake,传递NDK和工具链的路径。替代方案——基于Android.mk和Application.mk的NDK Build。

CMake 3.22+支持针对不同配置的预设(CMakePresets.json):debug、release、profile,使用不同的优化标志。对于Android,使用NDK中的android.toolchain.cmake工具链,由Gradle在构建时自动替换。

cmake
# Android NDK项目的CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project("native-lib")

add_library(
    native-lib
    SHARED
    src/main/cpp/native-lib.cpp
    src/main/cpp/image_utils.cpp
)

target_include_directories(
    native-lib PRIVATE
    src/main/cpp/include
)

target_link_libraries(
    native-lib
    android
    log
    ${CMAKE_SOURCE_DIR}/libs/libjpeg.a
)

set_target_properties(
    native-lib PROPERTIES
    CXX_STANDARD 20
    CXX_STANDARD_REQUIRED ON
)

add_library(SHARED)创建一个.so库。target_link_libraries连接系统库android(用于JNI)和log(用于__android_log_print)。静态库libjpeg.a被链接用于处理JPEG图像。CXX_STANDARD 20启用C++20支持。

vcpkg和依赖管理

vcpkg — 微软的C++包管理器,支持Android NDK作为目标平台。通过vcpkg可以安装Boost、OpenCV、SQLite、nlohmann-json和其他为Android ABI编译的库。Vcpkg通过CMAKE_TOOLCHAIN_FILE与CMake集成。

C++在移动设备上的性能

C++由于编译为原生ARM代码且没有垃圾回收器,在移动设备上提供最大性能。根据Google的测试(Android Performance Patterns,2024),对于计算密集型任务,C++中的JNI代码执行速度比等效Java代码快3-10倍。

移动平台上C++性能的关键因素:缓存局部性(数据在连续内存中的放置)、用于ARM的NEON SIMD指令、通过消息队列与JNI异步工作。NEON — ARM的SIMD扩展,允许在一条指令中处理128位数据,对于音频、视频和图像处理不可或缺。

cpp
// 通过NEON intrinsics进行数组的SIMD处理
#include <arm_neon.h>

void process_audio_neon(float *data, size_t n) {
    for (size_t i = 0; i < n; i += 4) {
        float32x4_t vec = vld1q_f32(&data[i]);
        float32x4_t result = vmulq_f32(vec, vdupq_n_f32(0.5f));
        vst1q_f32(&data[i], result);
    }
}

vld1q_f32从内存加载4个float到128位NEON寄存器。vmulq_f32在一个周期内将所有4个元素乘以0.5。vst1q_f32将结果存回。没有SIMD,相同的循环将顺序执行4次乘法——NEON为此类操作提供高达4倍的加速。

操作C++(毫秒)Java/Kotlin(毫秒)加速
处理1920x1080图像12453.75倍
快速傅里叶变换(FFT)8344.25倍
加密AES-256 1MB块3186倍
ZLIB数据压缩5224.4倍

在移动项目中使用C++的常见错误

第一个也是最危险的错误——内存泄漏。每个new必须有对应的delete,每个new[]必须有delete[]。在内存有限的移动设备上,任何泄漏都会导致OOM(Out Of Memory)和应用程序崩溃。通过智能指针使用RAII:std::unique_ptr、std::shared_ptr、std::weak_ptr。

第二个错误——忽略ABI兼容性。为armeabi-v7a编译的库无法在ARM64设备上加载。始终在build.gradle中指定abiFilters,并在真实设备上测试,而不仅仅是x86_64模拟器。使用Android App Bundle进行自动ABI过滤。

第三个常见错误——频繁的JNI调用。Java和C++之间的每次转换大约需要50-100纳秒。如果通过JNI逐个处理10000个元素的数组,开销将超过实际工作。将数据作为完整数组传递并在C++端处理。

多线程问题 — 另一个常见错误。C++可以启动std::thread,但只能从Java创建的线程访问JNI。要从C++线程调用Java方法,请通过JNI使用AttachCurrentThread / DetachCurrentThread。

cpp
// 从C++线程正确调用Java
JavaVM *g_vm; // 在JNI_OnLoad获取的全局指针

void background_task() {
    JNIEnv *env;
    jint res = g_vm->AttachCurrentThread(&env, nullptr);
    if (res == JNI_OK) {
        jclass clazz = env->FindClass("com/example/App");
        jmethodID mid = env->GetStaticMethodID(clazz, "onProgress", "(I)V");
        env->CallStaticVoidMethod(clazz, mid, 100);
        g_vm->DetachCurrentThread();
    }
}

常见问题

什么是Android NDK以及为什么在其中使用C++?

Android NDK(Native Development Kit) — 用于用C或C++编写应用程序部分的工具集。它用于对性能关键的任务、将C/C++库移植到Android以及实现Unity和Unreal Engine的跨平台代码。

哪些Unity游戏是用C++编写的?

Unity中,游戏逻辑代码用C#编写,但C++与Android NDK结合用于插件、处理硬件加速、移植专有C++库以及集成用于广告和分析的原生SDK。

如何为Android上的C++配置CMakeLists.txt?

CMakeLists.txt描述源文件、库和编译标志。最小配置包括用于构建.so的add_library和用于连接Android log和其他系统库的target_link_libraries。

C++中的JNI在Android上是必需的吗?

JNI(Java Native Interface) — Android应用程序的Java/Kotlin代码和C++库之间的中间层。如果从Java调用C++,则JNI是必需的。可以完全通过NDK编写C++代码,但入口点通常是调用原生函数的Java Activity。

在移动开发中何时使用C++替代Kotlin是合理的?

C++适用于游戏、实时音频/视频处理、计算机视觉、密码学、物理模拟以及从其他平台移植库。对于普通的UI应用程序,Kotlin更高效、更简单。

总结

  • C++ — 一种多范式语言,具有手动内存管理,用于Android NDK、Unity和Unreal Engine中的高性能代码
  • Android NDK使用LLVM的Clang工具链将C++编译为ARM架构的.so库
  • Unreal Engine完全基于C++构建,具有UHT反射系统,Unity在渲染和物理核心中使用C++
  • JNI — Android上Java/Kotlin与C++之间的必要桥梁,命名约定为Java_<包>_<类>_<方法>
  • CMake — NDK中C++的主要构建系统,支持C++20和与Gradle的集成
  • NEON SIMD通过128位向量指令在ARM处理器上提供高达4倍的数据处理加速
  • 常见错误:内存泄漏、abiFilters中的错误ABI、频繁的JNI调用以及没有AttachCurrentThread的多线程

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读