-
Notifications
You must be signed in to change notification settings - Fork 881
cpp: add Android backend support #11628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 6 commits
5f73e4f
eb2fdad
0aa0fe8
47920be
079f353
b7fd64c
85ce0f0
bb30ab0
841152a
b633213
a6ac20d
3107315
6493c4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,40 @@ endif () | |
| list(PREPEND CMAKE_MODULE_PATH ${Corrosion_SOURCE_DIR}/cmake) | ||
| find_package(Rust 1.92 REQUIRED MODULE) | ||
|
|
||
| # When building for Android (NDK toolchain sets CMAKE_SYSTEM_NAME to "Android"), | ||
| # auto-configure the Rust target, enable the android backend, and set sensible defaults. | ||
| # This block must run before the feature options are defined so that the forced cache values | ||
| # are picked up by define_cargo_feature / define_cargo_dependent_feature. | ||
| if(ANDROID) | ||
| # Map Android ABI to Rust target triple | ||
| if(ANDROID_ABI STREQUAL "arm64-v8a") | ||
| set(Rust_CARGO_TARGET "aarch64-linux-android" CACHE STRING "" FORCE) | ||
| elseif(ANDROID_ABI STREQUAL "armeabi-v7a") | ||
| set(Rust_CARGO_TARGET "armv7-linux-androideabi" CACHE STRING "" FORCE) | ||
| elseif(ANDROID_ABI STREQUAL "x86_64") | ||
| set(Rust_CARGO_TARGET "x86_64-linux-android" CACHE STRING "" FORCE) | ||
| elseif(ANDROID_ABI STREQUAL "x86") | ||
| set(Rust_CARGO_TARGET "i686-linux-android" CACHE STRING "" FORCE) | ||
| else() | ||
| message(FATAL_ERROR "Unsupported ANDROID_ABI: ${ANDROID_ABI}") | ||
| endif() | ||
|
|
||
| # Android requires a shared library | ||
| set(BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if these defaults could be set at the source instead of here with these kind of ugly overrides. We're in the right file, aren't we?:)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree. Although these are not default but mandatory features
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated the comment to say "Android requires the skia renderer and cannot use desktop backends".
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could integrate it into the Want me to try that approach? It would replace the FORCE overrides with conditions on the feature definitions themselves.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If mandatory perhaps that should become an option in the macro/function. But IMO it's sufficient if defaults are on/off correctly and it's all in one place. My concern is that if we remove/rename the feature we need to look at multiple places. (Not a super big issue but worth research if it can be done better) |
||
|
|
||
| # Enable the android backend and skia renderer, disable desktop backends | ||
| set(SLINT_FEATURE_BACKEND_ANDROID_ACTIVITY ON CACHE BOOL "" FORCE) | ||
| set(SLINT_FEATURE_RENDERER_SKIA ON CACHE BOOL "" FORCE) | ||
| set(SLINT_FEATURE_BACKEND_WINIT OFF CACHE BOOL "" FORCE) | ||
| set(SLINT_FEATURE_BACKEND_QT OFF CACHE BOOL "" FORCE) | ||
| set(SLINT_FEATURE_RENDERER_FEMTOVG OFF CACHE BOOL "" FORCE) | ||
|
|
||
|
ruminorix marked this conversation as resolved.
Outdated
|
||
| # Default to Material style on Android | ||
| if(NOT SLINT_STYLE) | ||
| set(SLINT_STYLE "material" CACHE STRING "" FORCE) | ||
| endif() | ||
| endif() | ||
|
|
||
| option(BUILD_SHARED_LIBS "Build Slint as shared library" ON) | ||
| option(SLINT_FEATURE_COMPILER "Enable support for compiling .slint files to C++ ahead of time" ON) | ||
| add_feature_info(SLINT_FEATURE_COMPILER SLINT_FEATURE_COMPILER "Enable support for compiling .slint files to C++ ahead of time") | ||
|
|
@@ -111,6 +145,8 @@ define_cargo_dependent_feature(backend-qt "Enable Qt based rendering backend" OF | |
| define_cargo_dependent_feature(backend-linuxkms "Enable support for the backend that renders a single window fullscreen on Linux. Requires libseat. If you don't have libseat, select `backend-linuxkms-noseat` instead." OFF "NOT SLINT_FEATURE_FREESTANDING") | ||
| define_cargo_dependent_feature(backend-linuxkms-noseat "Enable support for the backend that renders a single window fullscreen on Linux" OFF "NOT SLINT_FEATURE_FREESTANDING") | ||
|
|
||
| define_cargo_dependent_feature(backend-android-activity "Enable the Android backend for building Slint apps on Android" OFF "NOT SLINT_FEATURE_FREESTANDING") | ||
|
|
||
| define_cargo_dependent_feature(gettext "Enable support of translations using gettext" OFF "NOT SLINT_FEATURE_FREESTANDING") | ||
| define_cargo_dependent_feature(accessibility "Enable integration with operating system provided accessibility APIs" ON "NOT SLINT_FEATURE_FREESTANDING") | ||
| define_cargo_dependent_feature(testing "Enable support for testing API (experimental)" ON "NOT SLINT_FEATURE_FREESTANDING") | ||
|
|
@@ -306,6 +342,41 @@ if (SLINT_BUILD_RUNTIME) | |
| ) | ||
| endif() | ||
|
|
||
| # Propagate Android NDK/SDK paths to the Rust build so that the android-activity | ||
| # backend can compile Java sources and produce DEX bytecode. | ||
| if(ANDROID) | ||
| if(DEFINED ENV{ANDROID_NDK_ROOT}) | ||
| set_property( | ||
| TARGET slint_cpp | ||
| APPEND | ||
| PROPERTY CORROSION_ENVIRONMENT_VARIABLES | ||
| "ANDROID_NDK_ROOT=$ENV{ANDROID_NDK_ROOT}" | ||
| ) | ||
| elseif(CMAKE_ANDROID_NDK) | ||
| set_property( | ||
| TARGET slint_cpp | ||
| APPEND | ||
| PROPERTY CORROSION_ENVIRONMENT_VARIABLES | ||
| "ANDROID_NDK_ROOT=${CMAKE_ANDROID_NDK}" | ||
| ) | ||
| endif() | ||
| if(DEFINED ENV{ANDROID_HOME}) | ||
| set_property( | ||
| TARGET slint_cpp | ||
| APPEND | ||
| PROPERTY CORROSION_ENVIRONMENT_VARIABLES | ||
| "ANDROID_HOME=$ENV{ANDROID_HOME}" | ||
| ) | ||
| elseif(CMAKE_ANDROID_SDK) | ||
| set_property( | ||
| TARGET slint_cpp | ||
| APPEND | ||
| PROPERTY CORROSION_ENVIRONMENT_VARIABLES | ||
| "ANDROID_HOME=${CMAKE_ANDROID_SDK}" | ||
| ) | ||
| endif() | ||
| endif() | ||
|
|
||
| if(SLINT_FEATURE_RENDERER_SKIA OR SLINT_FEATURE_RENDERER_SKIA_OPENGL OR SLINT_FEATURE_RENDERER_SKIA_VULKAN) | ||
| find_program(CLANGCC clang) | ||
| find_program(CLANGCXX clang++) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Slint C++ Android Template | ||
|
ruminorix marked this conversation as resolved.
Outdated
|
||
|
|
||
| This directory contains a template project for building Slint C++ applications | ||
| on Android using Gradle and CMake. | ||
|
|
||
| See the [Slint C++ Android documentation](https://slint.dev/docs/guide/platforms/mobile/android-cpp) | ||
| for detailed instructions. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| 1. Copy this directory to create your project. | ||
|
|
||
| 2. Set up the required environment variables: | ||
| ```sh | ||
| export ANDROID_HOME=$HOME/Android/Sdk | ||
| export ANDROID_NDK_ROOT=$ANDROID_HOME/ndk/<version> | ||
| ``` | ||
|
|
||
| 3. Install the Rust Android target: | ||
| ```sh | ||
| rustup target add aarch64-linux-android | ||
| ``` | ||
|
|
||
| 4. Edit `app/src/main/cpp/main.cpp` and `app/src/main/cpp/main.slint` with | ||
| your application code. | ||
|
|
||
| 5. Build and deploy: | ||
| ```sh | ||
| ./gradlew installDebug | ||
| ``` | ||
|
|
||
| ## Project Structure | ||
|
|
||
| - `app/build.gradle.kts` - Android app configuration (SDK versions, CMake setup) | ||
| - `app/src/main/AndroidManifest.xml` - Android manifest with NativeActivity | ||
| - `app/src/main/cpp/CMakeLists.txt` - CMake build for C++ code and Slint | ||
| - `app/src/main/cpp/main.cpp` - Application entry point (`slint_main`) | ||
| - `app/src/main/cpp/main.slint` - Slint UI definition | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // Copyright © SixtyFPS GmbH <info@slint.dev> | ||
| // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
|
||
| plugins { | ||
| id("com.android.application") | ||
| } | ||
|
|
||
| android { | ||
| namespace = "dev.slint.app" | ||
| compileSdk = 35 | ||
|
|
||
| defaultConfig { | ||
| applicationId = "dev.slint.app" | ||
| // API 26 required for InMemoryDexClassLoader used by the Slint Android backend | ||
| minSdk = 26 | ||
| targetSdk = 35 | ||
| versionCode = 1 | ||
| versionName = "1.0" | ||
|
|
||
| ndk { | ||
| // Add other ABIs as needed: "armeabi-v7a", "x86_64", "x86" | ||
| abiFilters += "arm64-v8a" | ||
| } | ||
| } | ||
|
|
||
| buildTypes { | ||
| release { | ||
| isMinifyEnabled = false | ||
| } | ||
| } | ||
|
|
||
| externalNativeBuild { | ||
| cmake { | ||
| path = file("src/main/cpp/CMakeLists.txt") | ||
| version = "3.22.1" | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| <!-- Copyright © SixtyFPS GmbH <info@slint.dev> --> | ||
| <!-- SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 --> | ||
|
|
||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| <application | ||
| android:label="Slint App" | ||
| android:hasCode="false"> | ||
| <activity | ||
| android:name="android.app.NativeActivity" | ||
| android:exported="true" | ||
| android:configChanges="orientation|screenSize|keyboardHidden"> | ||
| <meta-data | ||
| android:name="android.app.lib_name" | ||
| android:value="app" /> | ||
| <intent-filter> | ||
| <action android:name="android.intent.action.MAIN" /> | ||
| <category android:name="android.intent.category.LAUNCHER" /> | ||
| </intent-filter> | ||
| </activity> | ||
| </application> | ||
| </manifest> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Copyright © SixtyFPS GmbH <info@slint.dev> | ||
| # SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
|
||
| cmake_minimum_required(VERSION 3.21) | ||
| project(SlintApp LANGUAGES CXX) | ||
|
|
||
| include(FetchContent) | ||
| FetchContent_Declare( | ||
| Slint | ||
| GIT_REPOSITORY https://github.com/slint-ui/slint.git | ||
| GIT_TAG v1.17.0 | ||
| SOURCE_SUBDIR api/cpp | ||
| ) | ||
| FetchContent_MakeAvailable(Slint) | ||
|
|
||
| add_library(app SHARED main.cpp) | ||
| target_link_libraries(app PRIVATE Slint::Slint) | ||
| slint_target_sources(app main.slint) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // Copyright © SixtyFPS GmbH <info@slint.dev> | ||
| // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
|
||
| #include "main.h" // Generated from main.slint | ||
|
|
||
| // Entry point for Slint applications on Android. | ||
| // The Slint runtime takes care of Android platform initialization; | ||
| // this function is called once the platform is ready. | ||
| extern "C" void slint_main() | ||
| { | ||
| auto window = MainWindow::create(); | ||
| window->run(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // Copyright © SixtyFPS GmbH <info@slint.dev> | ||
| // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
|
||
| export component MainWindow inherits Window { | ||
| preferred-width: 360px; | ||
| preferred-height: 640px; | ||
|
|
||
| VerticalLayout { | ||
| alignment: center; | ||
|
|
||
| Text { | ||
| text: "Hello from Slint on Android!"; | ||
| horizontal-alignment: center; | ||
| font-size: 24px; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| // Copyright © SixtyFPS GmbH <info@slint.dev> | ||
| // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
|
||
| plugins { | ||
| id("com.android.application") version "8.7.0" apply false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Copyright © SixtyFPS GmbH <info@slint.dev> | ||
| # SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
|
||
| android.useAndroidX=true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # Copyright © SixtyFPS GmbH <info@slint.dev> | ||
| # SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
|
||
| distributionBase=GRADLE_USER_HOME | ||
| distributionPath=wrapper/dists | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip | ||
| zipStoreBase=GRADLE_USER_HOME | ||
| zipStorePath=wrapper/dists |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // Copyright © SixtyFPS GmbH <info@slint.dev> | ||
| // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
|
||
| pluginManagement { | ||
| repositories { | ||
| google() | ||
| mavenCentral() | ||
| gradlePluginPortal() | ||
| } | ||
| } | ||
|
|
||
| dependencyResolution { | ||
| repositories { | ||
| google() | ||
| mavenCentral() | ||
| } | ||
| } | ||
|
|
||
| rootProject.name = "SlintApp" | ||
| include(":app") |
Uh oh!
There was an error while loading. Please reload this page.