Skip to content

Add Android port#1909

Open
SSimco wants to merge 21 commits into
cemu-project:mainfrom
SSimco:android
Open

Add Android port#1909
SSimco wants to merge 21 commits into
cemu-project:mainfrom
SSimco:android

Conversation

@SSimco

@SSimco SSimco commented May 9, 2026

Copy link
Copy Markdown
Collaborator

This PR contains the Android port of Cemu, as well as the necessary core code changes used by the Android port.

The Android app implements most features available in the wxWidgets GUI, except for the download manager and a few minor features.

The dependencies on Android are also handled using vcpkg, just like on other platforms.
All vcpkg dependencies that are either not used on Android or do not compile are marked with "platform": "!android" in vcpkg.json,
while dependencies exclusive to the Android port are marked with "platform": "android".

I've also added some other dependencies for the android port:

  • libadrenotools: for loading custom GPU drivers.
  • boost-context: for the fcontext fiber implementation, since the ucontext APIs (swapcontext, makecontext, getcontext) are not available on Android.
  • boost-stacktrace: because Android's Bionic libc does not include a standard backtrace() implementation. I used boost-stacktrace for logging stack traces on exceptions.
  • boost-iostreams: for reading files opened through Android's SAF.
  • stb: provides stb_image.h for decoding TGA image for game icons, as Android does not have a native API for this.

For translations on android, I used kotlinx-gettext, so most of the translations from wxWidgets can be shared with the Android app.
The only caveat is that this library doesn’t yet support .mo files, so I had to convert the existing translations back to .po files.
Also, some translations had to be changed to be compatible with the android app, like using Java formatting instead of C++ formatting (The persistent id {:x} is already in use by account {}! -> The persistent id {0} is already in use by account {1}!) or removing the shortcut from the translation (e.g. &Console language -> Console language).
I will update the workflow for generating the POT file to also include the Kotlin code once the gettext library is updated. Right now, the plugin that scans the Kotlin code from that library is not compatible with the Kotlin version used by the Android app.

The app is built mainly with Jetpack Compose components.
The only exceptions are some components that use SurfaceView.
For example, the emulation surface, which provides a surface handle to the native Vulkan renderer so it can create a Vulkan surface and draw to it.
And the input overlay, which implements the custom on-screen touch controls.

The Android app follows a feature-based architecture, where most features are placed in separate packages (e.g., settings, titlemanager, emulation) and are designed not to depend on each other. The only exceptions are external libraries and the core packages (common and nativeinterface). The CemuApplication class is responsible for app-wide initialization, such as loading the native library, configuring shared preferences, and loading translations. The MainActivity class integrates the UI from the different features into a single place by setting up navigation between components. I have also implemented a test (ArchitectureTests) that checks for this architectural rule.

High-level architecture diagram of the android app
flowchart LR
    subgraph entrypoints["Entry points"]
        direction RL
        info.cemu.cemu.MainActivity
        info.cemu.cemu.CemuApplication
    end

    subgraph Features
        direction RL
        info.cemu.cemu.about.*
        info.cemu.cemu.emulation.*
        info.cemu.cemu.gamelist.*
        info.cemu.cemu.graphicpacks.*
        info.cemu.cemu.provider.*
        info.cemu.cemu.settings.*
        info.cemu.cemu.titlemanager.*
    end

    subgraph Core
        Common["info.cemu.cemu.common.*"]
        Native["info.cemu.cemu.nativeinterface.*"]
    end

    Features -->|"Depends on"| Core
    entrypoints -->|"Depends on"| Features
    entrypoints -->|"Depends on"| Core
    Common -->|"Depends on"| Native
Loading

The job that builds the Android app also requires a signing key to be configured in the repository secrets. The secrets are only passed when a release is deployed. If it’s a build check for a PR, the app is signed with the debug keys.

To generate a signing key for the build workflow
key_alias=... # Create a repository secret named "ANDROID_KEY_ALIAS" with this alias
key_pass=...  # Create a repository secret named "ANDROID_KEY_PASS" with this password

# apt install default-jre # for keytool
keytool -genkey -noprompt -validity 10000 \
 -alias $key_alias \
 -dname "CN=Cemu Emulator,OU=Development,O=Cemu Project,L=Internet,C=XX" \
 -keystore keystore.jks \
 -storepass $key_pass \
 -keypass $key_pass \
 -keyalg RSA

# store the content of keystore_base64.txt in a repository secret name `ANDROID_STORE_FILE_BASE64`
base64 -w0 keystore.jks > keystore_base64.txt

For now, I think this state of the app is fine as a first version with basic android support.

@Crementif

Crementif commented May 14, 2026

Copy link
Copy Markdown
Member

Hey, thanks for your work.

Just giving you a heads-up that we are probably going to release Cemu 2.7 (partially due to the security incident) released before we look into merging any new PRs that might break things. But didn't want to keep you hanging without any answers for too long.

@BeezBumba

Copy link
Copy Markdown

I have a question. On my mali-g610 linux system, how come using this fork makes my Vulkan device get recognized. Did you change anything overall for vulkan in this.

@SSimco

SSimco commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator Author

I have a question. On my mali-g610 linux system, how come using this fork makes my Vulkan device get recognized. Did you change anything overall for vulkan in this.

Yes. I've updated the render to check features if they are available before enabling them. You could check the diffs made in the vulkan render.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants