This is a CMake template for LeviLauncher Android native mods. It includes a
ready-to-use manifest.json, CMake project, minimal MyMod, packaging script,
typed config generation, and GitHub Actions workflow.
.
├── CMakeLists.txt
├── manifest.json.in
├── scripts/package.ps1
└── src
├── config_generator.cpp
├── main.cpp
└── mod
├── Config.cpp
├── MyMod.cpp
└── MyMod.h
- Android SDK
- Android NDK 28.2.13676358 or a compatible version
- CMake 3.22+
- Ninja
- PowerShell 7+, or Windows PowerShell
The CMake project fetches preloader-android from https://github.com/LiteLDev/preloader-android automatically.
Set LEVI_PRELOADER_ROOT, pass -DLEVI_PRELOADER_ROOT=<path>, or use
scripts/package.ps1 -PreloaderRoot <path> only when you want to use a local
preloader-android checkout.
$env:ANDROID_HOME = "C:/Users/<you>/AppData/Local/Android/Sdk"
./scripts/package.ps1 -Abi arm64-v8aBuild both Android architectures:
./scripts/package.ps1 -Abi allAfter the build finishes, import the generated .levipack into LeviLauncher.
Common CMake options:
cmake -S . -B build-arm64-v8a `
-G Ninja `
-DCMAKE_TOOLCHAIN_FILE="$env:ANDROID_HOME/ndk/28.2.13676358/build/cmake/android.toolchain.cmake" `
-DANDROID_ABI=arm64-v8a `
-DANDROID_PLATFORM=android-28 `
-DANDROID_STL=c++_shared `
-DMOD_ID=my-mod `
-DMOD_NAME="My Mod" `
-DMOD_AUTHOR="LiteLDev" `
-DMOD_VERSION=0.1.0 `
-DMOD_LIBRARY_NAME=my_mod `
-DMOD_MINECRAFT_VERSIONS='["1.21.*"]' `
"-DMOD_ICON="
cmake --build build-arm64-v8a --target levi_packageWrite your mod logic in src/mod/MyMod.cpp:
bool MyMod::load() {
getSelf().getLogger().debug("Loading...");
return true;
}
bool MyMod::enable() {
getSelf().getLogger().debug("Enabling...");
return true;
}
bool MyMod::disable() {
getSelf().getLogger().debug("Disabling...");
return true;
}
bool MyMod::unload() {
getSelf().getLogger().debug("Unloading...");
return true;
}Lifecycle meaning:
load()runs when the mod is loaded.enable()runs before the game starts.disable()runs when the game is closing.unload()runs during final mod cleanup.
Common APIs:
getLogger()getId()getName()getModDir()getDataDir()getConfigDir()getResourceDir()getManifestPath()getLibraryPath()getJavaVM()
Use getDataDir() and getConfigDir() for your mod's own data and config
files.
The template includes a minimal typed config in src/mod/MyMod.h:
struct ModConfig {
int version = 1;
bool enabled = true;
std::string message = "Hello from My Mod";
};MyMod::load() uses pl::config::ConfigFile<ModConfig> to create and update
config/config.json. The package script runs src/config_generator.cpp before
Android compilation and includes generated config.json and
config.schema.json in the .levipack.
Keep this config small for your starter mod. Move larger examples, advanced schema coverage, or behavior tests into a separate project.