Bevy to Android

  • This post is a followup to the guide for Bevy 0.13, where a lot has changed.
  • These steps were done on an Apple M1 (2021) running Sequoia 15.3, and I deployed to a Pixel 9 phone.

Quickstart

Grab the following script and run it to create the necessary directory structure.

github gist: setup script

# Save the script above as setup.sh and then run it:
chmod +x setup.sh
./setup.sh

# Then load your project in android studio, and click: Run 'app'

When you run with Android Studio, you’ll be able to interact with your device in the app (under Running Devices), or on your phone directly.

Android Studio

If you choose not to use the script, the manual steps are under Android Structure.

Tools

Starting Project Structure

We’ll start with a generic bevy app.

cargo new bevy_breakout_15
cd bevy_breakout_15
cargo add bevy@0.15.2

mkdir assets
touch src/lib.rs

# For later:
brew install gradle
cargo install --locked cargo-ndk

Your project structure should look like this:

bevy_breakout_15
    assets/
    src/
        lib.rs
        main.rs
    Cargo.toml

Cargo.toml

name = "bevy_breakout_15"
version = "0.1.0"
edition = "2021"

[dependencies]
bevy = "0.15.2"

main.rs

fn main() {
    bevy_breakout_15::run_game();
}

lib.rs

Find the full lib.rs that I used for the Breakout game here.

use bevy::prelude::*;
// your dependencies
// ...

#[bevy_main]
fn main() {
    run_game();
}

pub fn run_game() {
    App::new()
        .add_plugins(DefaultPlugins)
        // your code
        // ...
        .run();
}

Android Structure

If you chose not to use the script, here are the manual steps.

Here, we’ll copy the necessary files from the bevy project, then modify them to suit our project (bevy_breakout_15).

Consider android_example your project root. So the files in here should be at the same level as your Cargo.toml and src/.

For every file inside: we want to copy them to our own project and modify the contents so example or android_example is replaced by our project name. My project is called bevy_breakout_15 so I’m going to replace all instances with that.

Copy exactly

  • gradle.properties
  • build.gradle: At the root of android_example
  • gradle/libs.versions.toml
  • app/CMakeLists.txt
  • app/src/main/cpp/dummy.cpp

Copy and modify

  • settings.gradle: change root.Project.name to bevy_breakout_15
  • app/build.gradle: change the two instances of org.bevyengine.example for org.bevyengine.bevy_breakout_15, then change the paths on assets.srcDirs and res.srcDirs to just point one directory up (../assets)
  • app/src/main/java/org/bevyengine/example/MainActivity.java: change the page to org/bevyengine/bevy_breakout_15, and edit MainActivity.java changing package org.bevyengine.example; and System.loadLibrary("bevy_mobile_example"); to package org.bevyengine.bevy_breakout_15; and System.loadLibrary("bevy_breakout_15");
  • app/src/main/AndroidManifest.xml: change Bevy Example to bevy_breakout_15, and bevy_mobile_example to bevy_breakout_15

Build for Android

  1. Make sure gradle is installed: brew install gradle
  2. Generate gradle/wrapper, gradlew, and gradle.bat with: gradle wrapper
  3. cargo ndk -t arm64-v8a -o app/src/main/jniLibs build --package bevy_breakout_15

Final Project structure

bevy_breakout_15
    app/
        src/
            main/
                cpp/
                java/
                    org/
                        bevyengine/
                            bevy_breakout_15/
                                MainActivity.java
                jniLibs/
                    arm64-v8a/
                        libbevy_breakout_15.so
                AndroidManifest.xml
        build.gradle
        CMakeLists.txt
    assets/
        android-res/
            mipmap-mdpi/
                ic_launcher.png
        sounds/
            breakout_collision.ogg
    src/
        lib.rs
        main.rs
    Cargo.toml

Cargo.toml

[package]
name = "bevy_breakout_15"
version = "0.1.0"
edition = "2021"

[dependencies]
bevy = "0.15.2"

[lib]
name = "bevy_breakout_15"
path = "src/lib.rs"
crate-type = [
    "staticlib",
    "cdylib",    # needed for Android
    "rlib",      # rlib needed for running locally
]

[[bin]]
name = "bevy_breakout_15"
path = "src/main.rs"

Rebuild

Anytime you want to re-build for android, make sure to run: cargo ndk -t arm64-v8a -o app/src/main/jniLibs build --package bevy_breakout_15, then click Run in Android Studio.

Resources

These resources made this post possible.