Loading a file from the assets directory of an Android apk in Rust

So this is something I couldnt find any reference for so heres a quick brain dump. Im using the egui winit example as a start.

Hiding the app pointer: Filesystem.rs

use winit::platform::android::activity::AndroidApp;

// provide layer between android and windows for loading files
#[derive( Debug)]
pub struct Filesystem {
    #[allow(dead_code)]
    #[cfg(target_os = "android")]
    pub(crate) app: AndroidApp
}

#[allow(dead_code)]
#[cfg(target_os = "android")]
pub fn read_asset_to_string(path: &str, app: &AndroidApp) -> Option<String> {
    let asset_manager = app.asset_manager();
    let path_cstring = std::ffi::CString::new(path).ok()?;
    let mut asset = asset_manager.open(&path_cstring)?;

    String::from_utf8(asset.get_buffer().ok()?.to_vec()).ok()
}

impl Filesystem {
    pub fn read_file(&self, filename: &String) -> Option<String> {
        #[cfg(target_os = "android")]
        return read_asset_to_string(filename, &self.app);
        #[cfg(not(target_os = "android"))]
        return std::fs::read_to_string(format!("./assets/{}", filename)).ok();
    }       
}

Reading the file

pub fn read_file(filename: String, fs: &Filesystem) -> Result<Settings, &'static str> {
        eprintln!("Reading file");

        if let Some(contents) = fs.read_file(&filename) {         
            eprintln!("\tLoaded [{filename}]");
            Ok(item)
        } else {
            eprintln!("\tNo file [{filename}]");
            Err("No [{filename}] file {err}")
        }
    }

Passing the Filesystem object around: lib.rs

#[cfg(not(target_os = "android"))]
pub fn main() {
    env_logger::builder()
        .filter_level(log::LevelFilter::Warn)
        .parse_default_env()
        .init();

    let event_loop = EventLoopBuilder::with_user_event().build();
    let fs = Filesystem {};
    _main(event_loop, fs);
}

#[allow(dead_code)]
#[cfg(target_os = "android")]
#[no_mangle]
fn android_main(app: AndroidApp) {
    use winit::platform::android::EventLoopBuilderExtAndroid;

    android_logger::init_once(
        android_logger::Config::default().with_max_level(log::LevelFilter::Warn),
    );

    let fs = Filesystem { app: app.clone() };
    let event_loop = EventLoopBuilder::with_user_event()
        .with_android_app(app)
        .build();
    stop_unwind(|| _main(event_loop, fs));
}

fn _main(event_loop: EventLoop<Event>, fs: Filesystem) {
    // Your code here
    read_file("settings.yaml".to_owned(), &fs);
}

Leave a comment