Skip to content
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

Android support for eframe #5318

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

parasyte
Copy link
Contributor

@parasyte parasyte commented Oct 28, 2024

Android support is "almost there". This PR pushes it just a bit further by allowing eframe to be used on Android. It works by smuggling the AndroidApp required by winit through NativeOptions.

The example isn't great because it doesn't leave space on the display for Android's top status bar or the lower navigation bar. I don't know what to do about that, yet. This is as far as I've managed to get it working.

Another problem is that the development environment setup is completely awful for Android unless you happen to already be a full-time Android developer with everything configured on your build host. As a Rustacean, this makes me very sad.

I've had some luck moving all of that mess to a container, adapted from https://github.com/SergioRibera/docker-rust-android. It takes care of all of the build dependencies, Android SDK, and the cargo-apk patches for bugs that I hit while getting the example to work on my device. (I also had to install an adb driver on my host and downloaded the Android platform-tools to get access to adb. An alternative is exposing the USB device to Docker. On Windows hosts, that means installing usbipd. A second alternative is using an mtp client to upload the APK as a file with USB file transfer enabled, then manually install it through the device's file manager.)

I'm not including the docker stuff in this PR, but here are the files and instructions for future reference (and it will probably simplify manual testing and CI, FWIW!)

Dockerfile
FROM rust:1.76.0-slim

# Variable arguments
ARG JAVA_VERSION=17
ARG NDK_VERSION=25.1.8937393
ARG BUILDTOOLS_VERSION=30.0.0
ARG PLATFORM_VERSION=android-30
ARG CLITOOLS_VERSION=8512546_latest

# Install Android requirements
RUN apt-get update -yqq && \
    apt-get install -y --no-install-recommends \
    libcurl4-openssl-dev libssl-dev pkg-config build-essential git python3 wget zip unzip openjdk-${JAVA_VERSION}-jdk && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# Install android targets
RUN rustup target add armv7-linux-androideabi aarch64-linux-android

# Install cargo-apk
RUN git clone -b fix/bin-targets-workspace-members https://github.com/parasyte/cargo-apk.git /tmp/cargo-apk && \
    cargo install --path /tmp/cargo-apk/cargo-apk

# Generate Environment Variables
ENV JAVA_VERSION=${JAVA_VERSION}
ENV ANDROID_HOME=/opt/Android
ENV NDK_HOME=/opt/Android/ndk/${NDK_VERSION}
ENV ANDROID_NDK_ROOT=${NDK_HOME}
ENV PATH=$PATH:${ANDROID_HOME}:${ANDROID_NDK_ROOT}:${ANDROID_HOME}/build-tools/${BUILDTOOLS_VERSION}:${ANDROID_HOME}/cmdline-tools/bin

# Install command line tools
RUN mkdir -p ${ANDROID_HOME}/cmdline-tools && \
    wget -qc "https://dl.google.com/android/repository/commandlinetools-linux-${CLITOOLS_VERSION}.zip" -P /tmp && \
    unzip -d ${ANDROID_HOME} /tmp/commandlinetools-linux-${CLITOOLS_VERSION}.zip && \
    rm -fr /tmp/commandlinetools-linux-${CLITOOLS_VERSION}.zip
# Install sdk requirements
RUN echo y | sdkmanager --sdk_root=${ANDROID_HOME} --install \
    "build-tools;${BUILDTOOLS_VERSION}" "ndk;${NDK_VERSION}" "platforms;${PLATFORM_VERSION}"

# Create APK keystore for debug profile
# Adapted from https://github.com/rust-mobile/cargo-apk/blob/caa806283dc26733ad8232dce1fa4896c566f7b8/ndk-build/src/ndk.rs#L393-L423
RUN keytool -genkey -v -keystore ${HOME}/.android/debug.keystore -storepass android -alias androiddebugkey \
    -keypass android -dname 'CN=Android Debug,O=Android,C=US' -keyalg RSA -keysize 2048 -validity 10000

# Cleanup
RUN rm -rf /tmp/*

WORKDIR /src

ENTRYPOINT [ "cargo", "apk", "build" ]
.dockerignore
# Ignore everything, only the Dockerfile is needed to build the container
*
docker build -t rust-android:latest .
docker run --rm -it -v "$PWD:/src" rust-android:latest -p hello_android
adb install target/debug/apk/hello_android.apk

Copy link

Preview available at https://egui-pr-preview.github.io/pr/5318-feature/android-eframe
Note that it might take a couple seconds for the update to show up after the preview_build workflow has completed.

@parasyte
Copy link
Contributor Author

The display safe area problem is tracked upstream at rust-windowing/winit#3910

@emilk emilk added the android label Oct 29, 2024
@lucasmerlin
Copy link
Collaborator

You can already use eframe on android by using a custom event_loop_builder:

  let options = NativeOptions {
    event_loop_builder: Some(Box::new(move |builder| {
      builder.with_android_app(app);
    })),
    ...
  }

But of course with your changes it gets easier to use eframe on android, so I think your change makes sense.

Also, having an example for android is great! What's your opinion on using cargo-mobile(2) instead of cargo-apk? I think that should allow us to have an example that works with both android and iOS.

@parasyte
Copy link
Contributor Author

parasyte commented Nov 6, 2024

What's your opinion on using cargo-mobile(2) instead of cargo-apk?

Great question! I have some personal opinions, such as my belief that it's difficult to make cross-platform apps which target mobile in part because there are so many unclear options. None of them stand out as obviously the best.

In the case of cargo-apk, there is some recent discussion about reviving it because their suggested replacement was considered a flop: rust-mobile/cargo-apk#66

There are two different projects with practically the same name, cargo-mobile and cargo-mobile2. The former was abandoned over 2 years ago and the latter is a fork by the tauri community (the same group that forked winit). The confusion this causes is unhelpful. And making things worse, the rust-mobile organization (maintainers of cargo-apk) want to bring both of these projects under their wing: BrainiumLLC/cargo-mobile#128

In short, it's a mess. cargo-apk aligns more closely with my preference for simplicity, at least for now.

I haven't looked at iOS yet. I can only imagine there are more differences than similarities.

@lucasmerlin
Copy link
Collaborator

lucasmerlin commented Nov 6, 2024

I see, I agree that the simplicity of cargo apk is nice. Maybe we can add support for cargo-mobile to the example once someone wants to update it to support ios as well.

Gave the example a try and it works great! (I already had the android sdk properly setup on my mac, so I didn't need any of the docker stuff)
But please add a note to the readme to install the android targets:

rustup target add aarch64-linux-android 
rustup target add armv7-linux-androideabi

@lucasmerlin lucasmerlin added the eframe Relates to epi and eframe label Nov 6, 2024
@lucasmerlin lucasmerlin marked this pull request as ready for review November 6, 2024 13:41
@parasyte
Copy link
Contributor Author

parasyte commented Nov 8, 2024

I added the requested target installation commands (so many things to track, I'm embarrassed I missed that), fixed the lfs issue, and rebased. This should be ready to go now.

@parasyte parasyte changed the title Experimental Android support for eframe Android support for eframe Nov 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android eframe Relates to epi and eframe
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants