From d5ebb6e6849f0dd225e7c379bec61b1c03d3b86a Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 19 Sep 2023 16:21:12 +0200 Subject: [PATCH] gradle: Embed assets in `baseAssets` "Play Asset Delivery" pack Assets for AABs could be embedded in the application pack but have significant limitations and size constraints. Implement the most simple form of an asset pack that comprises all assets listed in `manifest.yaml` in an `install-time` pack that is a fixed dependency of the app. This makes the files available to `AAssetManager` as soon as the app is started while being exempt of the 150MB limit. This matches the existing "asset embedding" functionality provided by our native APK build. https://developer.android.com/guide/playcore/asset-delivery/integrate-native --- xbuild/src/gradle/mod.rs | 56 +++++++++++++++++++++++++++++++ xbuild/src/gradle/settings.gradle | 1 + 2 files changed, 57 insertions(+) diff --git a/xbuild/src/gradle/mod.rs b/xbuild/src/gradle/mod.rs index 013bbdca..703d2f3f 100644 --- a/xbuild/src/gradle/mod.rs +++ b/xbuild/src/gradle/mod.rs @@ -67,6 +67,12 @@ pub fn build(env: &BuildEnv, out: &Path) -> Result<()> { dependencies.push_str(&format!("implementation '{}'\n", dep)); } + let asset_packs = if config.assets.is_empty() { + "" + } else { + r#"assetPacks = [":baseAssets"]"# + }; + let app_build_gradle = format!( r#" plugins {{ @@ -83,6 +89,7 @@ pub fn build(env: &BuildEnv, out: &Path) -> Result<()> { versionCode {version_code} versionName '{version_name}' }} + {asset_packs} }} dependencies {{ {dependencies} @@ -96,6 +103,55 @@ pub fn build(env: &BuildEnv, out: &Path) -> Result<()> { dependencies = dependencies, ); + let pack_name = "baseAssets"; + let base_assets = gradle.join(pack_name); + // Make sure that any possibly-obsolete asset pack does not clobber the build + let _ = std::fs::remove_dir_all(&base_assets); + + if !config.assets.is_empty() { + std::fs::create_dir_all(&base_assets)?; + let assets = format!( + r#" + plugins {{ + id 'com.android.asset-pack' + }} + assetPack {{ + packName = "{pack_name}" // Directory name for the asset pack + dynamicDelivery {{ + // Use install-time to make assets available to AAssetManager + // https://developer.android.com/guide/playcore/asset-delivery/integrate-native + deliveryType = "install-time" + }} + }} + "#, + ); + + std::fs::write(base_assets.join("build.gradle"), assets)?; + + let target_dir = base_assets.join("src/main/assets"); + let _ = std::fs::remove_dir_all(&target_dir); + std::fs::create_dir_all(&target_dir)?; + for asset in &config.assets { + let path = env.cargo().package_root().join(asset.path()); + let target = target_dir.join(asset.path().file_name().unwrap()); + + if !asset.optional() || path.exists() { + // Make this file or directory available to the `gradle` build system + + // Windows has special functions for files and directories: + // https://doc.rust-lang.org/std/fs/fn.soft_link.html + #[cfg(windows)] + if path.is_dir() { + std::os::windows::fs::symlink_dir(path, target)?; + } else { + std::os::windows::fs::symlink_file(path, target)?; + } + #[cfg(unix)] + std::os::unix::fs::symlink(path, target)?; + } + } + } + if let Some(icon_path) = env.icon.as_ref() { let mut scaler = xcommon::Scaler::open(icon_path)?; scaler.optimize(); diff --git a/xbuild/src/gradle/settings.gradle b/xbuild/src/gradle/settings.gradle index f60920c6..9f5af3eb 100644 --- a/xbuild/src/gradle/settings.gradle +++ b/xbuild/src/gradle/settings.gradle @@ -14,3 +14,4 @@ dependencyResolutionManagement { } include ':app' +include ':baseAssets'