From e7edc9557a5c223840c464e63e66cd30d2effbdd 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 | 54 ++++++++++++++++++++++++++++++- xbuild/src/gradle/settings.gradle | 1 + 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/xbuild/src/gradle/mod.rs b/xbuild/src/gradle/mod.rs index 013bbdca..6f083d9e 100644 --- a/xbuild/src/gradle/mod.rs +++ b/xbuild/src/gradle/mod.rs @@ -1,6 +1,6 @@ use crate::cargo::CrateType; use crate::{task, BuildEnv, Format, Opt}; -use anyhow::Result; +use anyhow::{Context, Result}; use std::path::Path; use std::process::Command; @@ -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,51 @@ 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 + xcommon::symlink(&path, &target).with_context(|| { + format!( + "Failed to make asset file/folder `{}` available to gradle at `{}`", + path.display(), + target.display() + ) + })?; + } + } + } + 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'