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

Merged
merged 1 commit into from
Dec 12, 2024
Merged

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

github-actions bot commented Oct 28, 2024

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

@parasyte parasyte force-pushed the feature/android-eframe branch from 76286b9 to 5ca2b43 Compare October 28, 2024 23:40
@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 parasyte force-pushed the feature/android-eframe branch 2 times, most recently from 6de10c3 to a0dd977 Compare November 8, 2024 20:45
@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
Repository owner deleted a comment from suprohub Dec 12, 2024
@emilk
Copy link
Owner

emilk commented Dec 12, 2024

I tried to fix the merge conflicts myself by alas
image

@parasyte
Copy link
Contributor Author

wut? I thought maintainers could do that. No worries, I'll get to it soon!

@emilk
Copy link
Owner

emilk commented Dec 12, 2024

I do see this O.o weird
image

@parasyte parasyte force-pushed the feature/android-eframe branch from a0dd977 to e1696c1 Compare December 12, 2024 16:12
@parasyte
Copy link
Contributor Author

Alright, I have completed the rebase.

@parasyte parasyte force-pushed the feature/android-eframe branch from e1696c1 to 2f5870d Compare December 12, 2024 16:15
@emilk emilk merged commit ea89c29 into emilk:master Dec 12, 2024
25 checks passed
@emilk
Copy link
Owner

emilk commented Dec 12, 2024

Thank you!

@parasyte parasyte deleted the feature/android-eframe branch December 12, 2024 18:40
@Swarkin

This comment was marked as resolved.

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.

5 participants