C++ в мобилната разработка: Android NDK, Unity и Unreal Engine

Автор: IT Sectr Публикувано: 2026-02-10 Време за четене: 11 мин

C++ — мултипарадигмен език за програмиране с ръчно управление на паметта, съчетаващ процедурно, обектно-ориентирано и обобщено програмиране. В мобилната разработка C++ се използва чрез Android NDK за портиране на библиотеки и чрез игровите двигатели Unity и Unreal Engine за създаване на крос-платформени игри. Според TIOBE (2026), C++ влиза в топ 5 езици по популярност сред професионалните разработчици.

Основни точки

  • C++ — език за системно програмиране, използван в Android NDK, Unity и Unreal Engine
  • Android NDK позволява компилиране на C++ код в естествени .so библиотеки за ARM процесори
  • Unreal Engine е изцяло изграден върху C++, а Unity използва C++ за нискостепенни добавки
  • JNI (Java Native Interface) — мостът между Java/Kotlin и C++ на Android
  • CMake и NDK Build — системи за изграждане на C++ проекти за мобилни платформи

Какво е C++?

C++ — език за програмиране, създаден от Бярне Страуструп през 1985 г. като разширение на C с поддръжка на класове. C++ осигурява директен достъп до паметта чрез указатели, шаблонно метапрограмиране и множествено наследяване. Стандартите C++17 и C++20 добавят корутини, концепти и ranges.

За разлика от Java и Kotlin, C++ няма събирач на отпадъци — разработчикът ръчно управлява заделянето и освобождаването на паметта чрез операторите new и delete. Това дава пълен контрол върху производителността, но изисква дисциплина. Според JetBrains Developer Survey (2025), 42% от C++ разработчиците използват езика в игровата индустрия.

Стандарти на C++ еволюират на всеки три години: C++11 (ламбди, auto, unique_ptr), C++14 (обобщени ламбди), C++17 (if constexpr, filesystem), C++20 (модули, корутини, концепти). Компилаторите Clang и GCC поддържат всички актуални стандарти, а за Android NDK се използва Clang от инструментариума LLVM.

Разлики между C++ и Java и Kotlin

Основната разлика на C++ от JVM езиците — ръчно управление на паметта и компилиране директно в машинен код. Java и Kotlin работят върху виртуална машина с автоматично събиране на отпадъци. C++ кодът се компилира в естествен двоичен файл за конкретна архитектура — ARM, x86 или RISC-V.

КритерийC++Java / Kotlin
Управление на паметтаРъчно (new/delete, RAII)Автоматично (Garbage Collector)
КомпилиранеЕстествен машинен кодБайт-код JVM / ART
ПроизводителностМаксимална (zero-cost abstractions)Висока с GC паузи
Използване в мобилната разработкаNDK, игри, библиотекиUI приложения, бизнес логика
ИзгражданеCMake, NDK Build, Gradle + NDKGradle, Maven
Крос-платформеностКомпилиране за всяка платформаJVM / ART навсякъде

C++ в мобилната разработка: Android NDK

Android NDK (Native Development Kit) — инструментариум на Google за писане на части от Android приложение на C и C++. NDK включва инструментариум, базиран на Clang, системни заглавни файлове на Android, библиотеки за отстраняване на грешки и профилиране. Версия r27 (2025) поддържа C++20 и използва LLVM 18.

NDK компилира C++ код в динамични .so библиотеки за архитектури ARM64, ARM32, x86 и x86_64. Java или Kotlin приложението зарежда тези библиотеки чрез System.loadLibrary() и извиква естествени функции чрез JNI. Според Google, NDK е изтеглен над 5 милиона пъти.

Структура на проект с NDK

Типичен проект с Android NDK съдържа папка app/src/main/cpp/ с изходни C++ файлове, CMakeLists.txt за изграждане и Java клас с декларация на естествени методи. Gradle свързва NDK чрез блока externalNativeBuild в build.gradle.

cpp
// native-lib.cpp — прост JNI метод за Android
#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());
}

Кодът декларира JNI функция с пълното име Java_com_example_app_MainActivity_stringFromJNI — това е конвенцията за именуване на JNI. Функцията приема указател към JNIEnv (среда за изпълнение) и jobject (екземпляр на извикващия клас). env->NewStringUTF създава Java низ от C++ низ.

ABI и целеви архитектури

Android поддържа няколко ABI (Application Binary Interface): arm64-v8a (64-битови ARM устройства, 99% от съвременните смартфони), armeabi-v7a (32-битови ARM, по-стари устройства), x86_64 (емулатори). NDK позволява изграждане на .so за всяка архитектура чрез ABI филтри в build.gradle.

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++ в ядрото на двигателя за рендиране и физика. Дори ако разработчикът пише на C# в Unity, под капака C++ управлява графиката, звука и физическите изчисления.

Unreal Engine: C++ като основен език

Unreal Engine е изграден върху C++ от нулата. Кодът на игровата логика се пише на 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: C++ в добавки и Native SDK

Unity използва C# за игрова логика, но C++ се прилага в Native Plugins — .so библиотеки за Android и .bundle за iOS. Чрез 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# маршалира извикването към C++ функцията ProcessFrame чрез P/Invoke. Атрибутът DllImport указва името на .so библиотеката. C++ функцията обработва кадъра в реално време и връща резултата. Този подход се използва за пост-ефекти и компютърно зрение.

JNI: взаимодействие между Java и C++

JNI (Java Native Interface) — стандартният механизъм за извикване на C/C++ код от Java или Kotlin. На Android JNI е единственият начин за прехвърляне на данни между виртуалната машина ART и естествената библиотека. Всяко JNI извикване има допълнителни разходи, поради което данните се прехвърлят на пакети, а не поле по поле.

JNIEnv — указател към таблицата на JNI функциите. env->FindClass зарежда Java клас, env->GetMethodID получава идентификатора на метода, env->CallVoidMethod го извиква. За низове се използват GetStringUTFChars и ReleaseStringUTFChars. JNI също поддържа глобални и слаби референции към Java обекти.

cpp
// Прехвърляне на байтов масив от C++ към Java чрез JNI
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 байтов масив. JNI_COMMIT в ReleaseByteArrayElements копира промените обратно в Java масива без да освобождава паметта. Обработката с for цикъл се извършва на CPU с максимална производителност на C++ без GC паузи.

Управление на паметта в JNI

Основната опасност на JNI — изтичане на глобални референции. Всеки NewGlobalRef трябва да бъде освободен чрез DeleteGlobalRef. Локалните референции (връщани от FindClass, NewStringUTF) се изтриват автоматично при връщане от естествената функция. За интензивни извиквания използвайте PushLocalFrame / PopLocalFrame.

CMake и системи за изграждане на C++ под Android

CMake — основният инструмент за изграждане на C++ в Android NDK. CMakeLists.txt описва целите за изграждане, библиотеките и зависимостите. Gradle извиква CMake чрез externalNativeBuild, предавайки пътища към NDK и инструментариума. Алтернатива — NDK Build, базиран на Android.mk и Application.mk.

CMake 3.22+ поддържа предварителни настройки (CMakePresets.json) за различни конфигурации: debug, release, profile с различни оптимизационни флагове. За Android се използва инструментариумът android.toolchain.cmake от NDK, който се замества автоматично от Gradle при изграждане.

cmake
# CMakeLists.txt за Android NDK проект
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++ от Microsoft, който поддържа Android NDK като целева платформа. Чрез vcpkg могат да се инсталират Boost, OpenCV, SQLite, nlohmann-json и други библиотеки, компилирани за Android ABI. Vcpkg се интегрира с CMake чрез CMAKE_TOOLCHAIN_FILE.

Производителност на C++ на мобилни устройства

C++ осигурява максимална производителност на мобилни устройства благодарение на компилиране до естествен ARM код и липсата на събирач на отпадъци. Според тестове на Google (Android Performance Patterns, 2024), JNI кодът на C++ се изпълнява 3–10 пъти по-бързо от еквивалентния Java код за задачи с интензивни изчисления.

Ключови фактори за производителността на C++ на мобилни платформи: кеш локалност (разполагане на данни в непрекъсната памет), SIMD инструкции NEON за ARM, асинхронна работа с JNI чрез опашки от съобщения. NEON — SIMD разширение на ARM, позволяващо обработка на 128 бита данни в една инструкция, незаменимо за обработка на аудио, видео и изображения.

cpp
// SIMD обработка на масив чрез NEON intrinsics
#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 дава ускорение до 4x за такива операции.

ОперацияC++ (ms)Java/Kotlin (ms)Ускорение
Обработка на изображение 1920x108012453.75x
Бързо преобразуване на Фурие (FFT)8344.25x
AES-256 криптиране на блок 1MB3186x
ZLIB компресия на данни5224.4x

Типични грешки при използване на C++ в мобилни проекти

Първата и най-опасна грешка — изтичане на памет. Всеки new трябва да има delete, всеки new[] — delete[]. На мобилни устройства с ограничена RAM всяко изтичане води до OOM (Out Of Memory) и срив на приложението. Използвайте RAII чрез умни указатели: std::unique_ptr, std::shared_ptr, std::weak_ptr.

Втора грешка — игнориране на ABI съвместимост. Библиотека, компилирана за armeabi-v7a, няма да се зареди на ARM64 устройство. Винаги указвайте abiFilters в build.gradle и тествайте на реални устройства, а не само на x86_64 емулатор. Използвайте Android App Bundle за автоматично филтриране на ABI.

Трета типична грешка — чести JNI извиквания. Всеки преход между Java и C++ струва около 50–100 ns. Ако обработвате масив от 10000 елемента един по един чрез JNI, допълнителните разходи ще надхвърлят полезната работа. Прехвърляйте данни като цели масиви и ги обработвайте от страна на C++.

Проблеми с многонишковостта — друга често срещана грешка. C++ може да стартира std::thread, но достъпът до JNI е възможен само от нишка, създадена от Java. За извикване на Java методи от C++ нишка използвайте AttachCurrentThread / DetachCurrentThread чрез JNI.

cpp
// Правилно извикване на Java от C++ нишка
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 за реклама и аналитика.

Как да конфигурираме CMakeLists.txt за C++ под Android?

CMakeLists.txt описва изходните файлове, библиотеките и флаговете за компилиране. Минималната конфигурация включва add_library за изграждане на .so и target_link_libraries за свързване на Android log и други системни библиотеки.

JNI в C++ задължителен ли е за Android?

JNI (Java Native Interface) — слоят между Java/Kotlin кода на Android приложението и C++ библиотеката. Ако C++ се извиква от Java, JNI е задължителен. Може да пишете C++ код изцяло чрез NDK, но входната точка обикновено е Java активност, която извиква естествени функции.

Кога C++ е оправдан вместо Kotlin в мобилната разработка?

C++ е оправдан за игри, обработка на аудио/видео в реално време, компютърно зрение, криптография, физически симулации и портиране на библиотеки от други платформи. За обикновено UI приложение Kotlin е по-ефективен и по-прост.

Обобщение

  • C++ — мултипарадигмен език с ръчно управление на паметта, използван в Android NDK, Unity и Unreal Engine за високопроизводителен код
  • Android NDK компилира C++ в .so библиотеки за ARM архитектури с инструментариума Clang от LLVM
  • Unreal Engine е изцяло изграден върху C++ със система за отражение UHT, Unity използва C++ в ядрото за рендиране и физика
  • JNI — задължителният мост между Java/Kotlin и C++ на Android с конвенция за именуване Java_<пакет>_<клас>_<метод>
  • CMake — основната система за изграждане на C++ в NDK, поддържаща C++20 и интеграция с Gradle
  • NEON SIMD осигурява до 4x ускорение на обработката на данни на ARM процесори чрез 128-битови векторни инструкции
  • Типични грешки: изтичане на памет, неправилен ABI в abiFilters, чести JNI извиквания и многонишковост без AttachCurrentThread

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също