slint/android.rs
1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore javac
5//! Android backend.
6//!
7//! **Note:** This module is only available on Android with the "backend-android-activity-06" feature
8//!
9//! Slint uses the [android-activity crate](https://github.com/rust-mobile/android-activity) as a backend.
10//!
11//! For convenience, Slint re-exports the content of the [`android-activity`](https://docs.rs/android-activity) under `slint::android::android_activity`.
12//!
13//! As with every application using the android-activity crate, the entry point to your app will be the `android_main` function.
14//! From that function, you can call [`slint::android::init`](init()) or [`slint::android::init_with_event_listener`](init_with_event_listener)
15//!
16//! # Example
17//!
18//! This is a basic example of an Android application.
19//! Do not forget the `#[unsafe(no_mangle)]`
20//!
21//! ```rust
22//! # #[cfg(target_os = "android")]
23//! #[unsafe(no_mangle)]
24//! fn android_main(app: slint::android::AndroidApp) {
25//! slint::android::init(app).unwrap();
26//!
27//! // ... rest of your code ...
28//! slint::slint!{
29//! export component MainWindow inherits Window {
30//! Text { text: "Hello World"; }
31//! }
32//! }
33//! MainWindow::new().unwrap().run().unwrap();
34//! }
35//! ```
36//!
37//! That function must be in a `cdylib` library, and you should enable the "backend-android-activity-06"
38//! feature of the slint crate in your Cargo.toml:
39//!
40//! ```toml
41//! [lib]
42//! crate-type = ["cdylib"]
43//!
44//! [dependencies]
45//! slint = { version = "1.6", features = ["backend-android-activity-06"] }
46//! ```
47//!
48//! ## Building and Deploying
49//!
50//! Building a Rust application requires the target toolchain to be installed. You can install it via `rustup`. For example, to target AArch64 Android, use the following command:
51//!
52//! ```sh
53//! rustup target add aarch64-linux-android
54//! ```
55//!
56//! Make sure that you have the Android NDK and SDK installed and set up in your development environment.
57//! For detailed instructions on how to set up the Android NDK and SDK, please refer to the [Android Developer's guide](https://developer.android.com/studio/projects/install-ndk).
58//! The following environment variables need to be set:
59//! * `ANDROID_HOME`: The directory in which your Android SDK is located. Usually `$HOME/Android/Sdk`.
60//! * `ANDROID_NDK_ROOT`: The directory in which your Android NDK is located. Usually `$HOME/Android/Sdk/ndk/${NDK_VERSION}`. ${NDK_VERSION} is the version of the NDK you have installed.
61//! * `JAVA_HOME`: The directory in which your Java compiler (`javac`) is located. This variable is optional if a `javac` is found in your `$PATH`.
62//! Otherwise you can set `JAVA_HOME` to the `javac` installation shipped with Android Studio in `android-studio/jbr`.
63//!
64//! To build and deploy your application, we suggest the usage of [cargo-apk](https://github.com/rust-mobile/cargo-apk),
65//! a cargo subcommand that allows you to build, sign, and deploy Android APKs made in Rust.
66//!
67//! You can install it and use it with the following command:
68//!
69//! ```sh
70//! cargo install cargo-apk
71//! ```
72//!
73//! Build and run your application with the following command:
74//!
75//! ```sh
76//! cargo apk run --target aarch64-linux-android --lib
77//! ```
78//!
79//!
80//! Note Slint does not require a specific build tool and can work with others, such as [xbuild](https://github.com/rust-mobile/xbuild).
81
82/// Re-export of the android-activity crate.
83#[cfg(all(
84 target_os = "android",
85 any(feature = "backend-android-activity-05", feature = "backend-android-activity-06")
86))]
87pub use i_slint_backend_android_activity::android_activity;
88
89#[cfg(not(all(
90 target_os = "android",
91 any(feature = "backend-android-activity-05", feature = "backend-android-activity-06")
92)))]
93/// Re-export of the [android-activity](https://docs.rs/android-activity) crate.
94pub mod android_activity {
95 #[doc(hidden)]
96 pub struct AndroidApp;
97 #[doc(hidden)]
98 pub struct PollEvent<'a>(&'a ());
99}
100
101/// Re-export of AndroidApp from the [android-activity](https://docs.rs/android-activity) crate.
102#[doc(no_inline)]
103pub use android_activity::AndroidApp;
104
105use crate::platform::SetPlatformError;
106
107/// Initializes the Android backend.
108///
109/// **Note:** This function is only available on Android with the "backend-android-activity-06" feature
110///
111/// This function must be called from the `android_main` function before any call to Slint that needs a backend.
112///
113/// See the [module documentation](self) for an example on how to create Android application.
114///
115/// See also [`init_with_event_listener`]
116pub fn init(app: android_activity::AndroidApp) -> Result<(), SetPlatformError> {
117 #[cfg(not(target_os = "android"))]
118 unreachable!();
119 #[cfg(target_os = "android")]
120 {
121 crate::platform::set_platform(Box::new(
122 i_slint_backend_android_activity::AndroidPlatform::new(app),
123 ))
124 }
125}
126
127/// Similar to [`init()`], which allow to listen to android-activity's event
128///
129/// **Note:** This function is only available on Android with the "backend-android-activity-06" feature
130///
131/// The listener argument is a function that takes a [`android_activity::PollEvent`](https://docs.rs/android-activity/latest/android_activity/enum.PollEvent.html)
132///
133/// # Example
134///
135/// ```rust
136/// # #[cfg(target_os = "android")]
137/// #[unsafe(no_mangle)]
138/// fn android_main(app: slint::android_activity::AndroidApp) {
139/// slint::android::init_with_event_listener(
140/// app,
141/// |event| { eprintln!("got event {event:?}") }
142/// ).unwrap();
143///
144/// // ... rest of your application ...
145///
146/// }
147/// ```
148///
149/// Check out the [module documentation](self) for a more complete example on how to write an android application
150pub fn init_with_event_listener(
151 app: android_activity::AndroidApp,
152 listener: impl Fn(&android_activity::PollEvent<'_>) + 'static,
153) -> Result<(), SetPlatformError> {
154 #[cfg(not(target_os = "android"))]
155 unreachable!();
156 #[cfg(target_os = "android")]
157 {
158 crate::platform::set_platform(Box::new(
159 i_slint_backend_android_activity::AndroidPlatform::new_with_event_listener(
160 app, listener,
161 ),
162 ))
163 }
164}