Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified assets/images/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 7 additions & 15 deletions crossbundle/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@ See [installation documentation](https://crossbow.dodorare.com/install/index.htm
## Cargo.toml Metadata syntax

```toml
[[package.metadata.android]]
[[package.metadata]]
# Cross-platform user-friendly application name for your app.
app_name = "Example"
# Cross-platform assets directory path relatively to project path.
assets = "assets"
assets = ["assets"]
# Cross-platform icon path to generate icons for Android and iOS.
icon = "../../assets/images/icon.png"

[[package.metadata.android]]
# Android application wrapper: supports ndk-glue and sokol
Expand All @@ -65,9 +67,9 @@ app_name = "Example"
# Path to AndroidManifest.xml file
manifest_path = "path/to/AndroidManifest.xml"
# Android resources directory path relatively to project path.
res = "res/android"
resources = ["res/android"]
# Android assets directory path relatively to project path.
assets = "assets"
assets = ["assets"]
# Android targets to build on debug or release.
debug_build_targets = ["aarch64-linux-android"]
release_build_targets = ["aarch64-linux-android"]
Expand Down Expand Up @@ -103,27 +105,17 @@ authorities = "org.khronos.openxr.runtime_broker;org.khronos.openxr.system_runti
# This will be made optional if/when cargo-apk migrates to aapt2.
name = "org.khronos.openxr"

# See https://developer.android.com/guide/topics/manifest/uses-feature-element
#
# Note: there can be multiple .uses_feature entries.
[[package.metadata.android.manifest.features]]
name = "android.hardware.vulkan.level"
required = true
version = 1

# See https://developer.android.com/guide/topics/manifest/meta-data-element
[[package.metadata.android.manifest.application.meta_data]]
name = "com.oculus.vr.focusaware"
value = "true"

[package.metadata.apple]
# The user-friendly application name for your app. Displayed in the applications menu
app_name = "Example"
# Apple targets to build on debug or release.
debug_build_targets = ["aarch64-apple-ios"]
release_build_targets = ["aarch64-apple-ios", "x86_64-apple-ios"]
# Apple resources directory path relatively to project path.
res = "res/apple"
resources = ["res/apple"]
```

## CLI options and flags
Expand Down
71 changes: 63 additions & 8 deletions crossbundle/cli/src/commands/build/android.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use super::{BuildContext, SharedBuildCommand};
use crate::error::Result;
use crate::{error::*, types::CrossbowMetadata};
use android_manifest::AndroidManifest;
use android_tools::java_tools::{JarSigner, Key};
use clap::Parser;
use crossbundle_tools::{commands::android::*, error::CommandExt, types::*};
use crossbundle_tools::{
commands::{android::*, combine_folders},
error::CommandExt,
types::*,
};
use std::path::{Path, PathBuf};

/// Specifies flags and options needed to build application
Expand Down Expand Up @@ -96,11 +100,15 @@ impl AndroidBuildCommand {
std::env::set_var("ANDROID_SDK_ROOT", sdk.sdk_path());
}

config.status("Preparing resources and assets")?;
let (assets, resources) =
Self::prepare_assets_and_resources(&context.config, &android_build_dir)?;

config.status("Generating gradle project")?;
let gradle_project_path = gen_gradle_project(
&android_build_dir,
&context.config.get_android_assets(),
&context.config.android.res,
&assets,
&resources,
&context.config.android.plugins,
)?;

Expand Down Expand Up @@ -196,6 +204,9 @@ impl AndroidBuildCommand {
let manifest = Self::get_android_manifest(context, AndroidStrategy::NativeApk)?;
config.status_message("Generating", "AndroidManifest.xml")?;
let manifest_path = save_android_manifest(&native_build_dir, &manifest)?;
config.status("Preparing resources and assets")?;
let (assets, resources) =
Self::prepare_assets_and_resources(&context.config, &android_build_dir)?;

config.status_message("Compiling", "lib")?;
let target_sdk_version = Self::target_sdk_version(&manifest, &sdk);
Expand All @@ -218,8 +229,8 @@ impl AndroidBuildCommand {
&project_path,
&native_build_dir,
&manifest_path,
&context.config.get_android_assets(),
&context.config.android.res,
&assets,
&resources,
&package_name,
target_sdk_version,
)?;
Expand Down Expand Up @@ -279,6 +290,9 @@ impl AndroidBuildCommand {
let manifest = Self::get_android_manifest(context, AndroidStrategy::NativeAab)?;
config.status_message("Generating", "AndroidManifest.xml")?;
let manifest_path = save_android_manifest(&native_build_dir, &manifest)?;
config.status("Preparing resources and assets")?;
let (assets, resources) =
Self::prepare_assets_and_resources(&context.config, &android_build_dir)?;

config.status_message("Compiling", "lib")?;
let target_sdk_version = Self::target_sdk_version(&manifest, &sdk);
Expand All @@ -297,7 +311,7 @@ impl AndroidBuildCommand {

config.status_message("Generating", "proto format APK file")?;

let compiled_res = if let Some(res) = &context.config.android.res {
let compiled_res = if let Some(res) = &resources {
let compiled_res_path = native_build_dir.join("compiled_res");
if !compiled_res_path.exists() {
std::fs::create_dir_all(&compiled_res_path)?;
Expand All @@ -316,7 +330,7 @@ impl AndroidBuildCommand {
let mut aapt2_link =
sdk.aapt2()?
.link_compiled_res(compiled_res, &apk_path, &manifest_path);
if let Some(assets) = &context.config.get_android_assets() {
if let Some(assets) = &assets {
aapt2_link.assets(assets.clone())
} else {
&mut aapt2_link
Expand Down Expand Up @@ -496,6 +510,7 @@ impl AndroidBuildCommand {
sdk.default_platform()
}

/// Get min sdk version from cargo manifest
pub fn min_sdk_version(android_manifest: &AndroidManifest) -> u32 {
android_manifest
.uses_sdk
Expand Down Expand Up @@ -547,4 +562,44 @@ impl AndroidBuildCommand {
});
Ok(manifest)
}

/// Prepare assets and resources for the application.
///
/// Also, this function will generate mipmap icon resources if specified in the
/// CrossbowMetadata config.
pub fn prepare_assets_and_resources(
config: &CrossbowMetadata,
out_dir: &Path,
) -> Result<(Option<PathBuf>, Option<PathBuf>)> {
let res = config.get_android_resources();
let gen_resources = if res.is_empty() && config.icon.is_none() {
None
} else {
let path = out_dir.join("gen_resources");
std::fs::remove_dir_all(&path).ok();
combine_folders(res, &path)?;

if let Some(icon) = &config.icon {
ImageGeneration {
icon_path: icon.to_owned(),
out_icon_name: "ic_launcher.png".to_owned(),
output_path: path.clone(),
force: true,
}
.gen_mipmap_res_from_icon()?;
}
Some(path)
};

let assets = config.get_android_assets();
let gen_assets = if !res.is_empty() {
let path = out_dir.join("gen_assets");
std::fs::remove_dir_all(&path).ok();
combine_folders(assets, &path)?;
Some(path)
} else {
None
};
Ok((gen_assets, gen_resources))
}
}
60 changes: 43 additions & 17 deletions crossbundle/cli/src/commands/build/apple.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use super::{BuildContext, SharedBuildCommand};
use crate::error::*;
use crate::{error::*, types::CrossbowMetadata};
use apple_bundle::prelude::InfoPlist;
use clap::Parser;
use crossbundle_tools::{commands::apple, types::*};
use crossbundle_tools::{
commands::{apple, combine_folders},
types::*,
};
use std::path::{Path, PathBuf};

#[derive(Parser, Clone, Debug)]
Expand Down Expand Up @@ -106,31 +109,24 @@ impl IosBuildCommand {
)?;
let out_dir = context.target_dir.join(rust_triple).join(&profile);
let bin_path = out_dir.join(&name);

config.status("Generating app folder")?;
let apple_target_dir = &context
.target_dir
.join("apple")
.join(rust_triple)
.join(&profile);
let app_path = apple::gen_apple_app_folder(
apple_target_dir,
name,
context
.config
.get_apple_assets()
.as_ref()
.map(|r| project_path.join(r)),
context
.config
.apple
.res
.as_ref()
.map(|r| project_path.join(r)),
)?;

config.status("Preparing resources and assets")?;
let (assets, resources) =
Self::prepare_assets_and_resources(&context.config, apple_target_dir)?;

let app_path = apple::gen_apple_app_folder(apple_target_dir, name, assets, resources)?;
config.status("Copying binary to app folder")?;
std::fs::copy(&bin_path, &app_path.join(&name)).unwrap();
config.status_message("Generating", "Info.plist")?;
apple::save_info_plist(&app_path, properties, false).unwrap();

if self.identity.is_some() {
config.status("Starting code signing process")?;
apple::copy_profile(
Expand All @@ -154,6 +150,7 @@ impl IosBuildCommand {
apple::codesign(&app_path, true, self.identity.clone(), Some(xcent_path))?;
config.status("Code signing process finished")?;
}

config.status("Generating ipa file")?;
apple::gen_apple_ipa(apple_target_dir, &app_path, name)?;
config.status("Build finished successfully")?;
Expand Down Expand Up @@ -199,4 +196,33 @@ impl IosBuildCommand {
});
Ok(info_plist)
}

/// Prepare assets and resources for the application.
pub fn prepare_assets_and_resources(
config: &CrossbowMetadata,
out_dir: &Path,
) -> Result<(Option<PathBuf>, Option<PathBuf>)> {
let res = config.get_apple_resources();
let gen_resources = if res.is_empty() && config.icon.is_none() {
None
} else {
let path = out_dir.join("gen_resources");
std::fs::remove_dir_all(&path).ok();
combine_folders(res, &path)?;

// TODO: Generate icons
Some(path)
};

let assets = config.get_apple_assets();
let gen_assets = if !res.is_empty() {
let path = out_dir.join("gen_assets");
std::fs::remove_dir_all(&path).ok();
combine_folders(assets, &path)?;
Some(path)
} else {
None
};
Ok((gen_assets, gen_resources))
}
}
10 changes: 8 additions & 2 deletions crossbundle/cli/src/types/android_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,17 @@ pub struct AndroidConfig {
/// **Important:** If this field specified - `manifest` property will be ignored.
pub manifest_path: Option<PathBuf>,
/// Android resources directory path relatively to project path.
pub res: Option<PathBuf>,
///
/// If specified more than one - all resources will be placed into one directory.
#[serde(default)]
pub resources: Vec<PathBuf>,
/// Custom Android assets directory path relatively to project path.
///
/// If specified more than one - all assets will be placed into one directory.
///
/// **Important:** This property has higher priority than global property.
pub assets: Option<PathBuf>,
#[serde(default)]
pub assets: Vec<PathBuf>,
/// Android debug build targets.
#[serde(default)]
pub debug_build_targets: Vec<AndroidTarget>,
Expand Down
10 changes: 8 additions & 2 deletions crossbundle/cli/src/types/apple_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ pub struct AppleConfig {
/// **Important:** If this field specified - `info_plist` property will be ignored.
pub info_plist_path: Option<PathBuf>,
/// Apple `resources` directory path relatively to project path.
pub res: Option<PathBuf>,
///
/// If specified more than one - all resources will be placed into one directory.
#[serde(default)]
pub resources: Vec<PathBuf>,
/// Custom Apple `assets` directory path relatively to project path.
///
/// If specified more than one - all assets will be placed into one directory.
///
/// **Important:** This property has higher priority than global property.
pub assets: Option<PathBuf>,
#[serde(default)]
pub assets: Vec<PathBuf>,
/// Apple debug build targets.
#[serde(default)]
pub debug_build_targets: Vec<IosTarget>,
Expand Down
37 changes: 30 additions & 7 deletions crossbundle/cli/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,22 @@ pub struct CrossbowMetadata {
pub app_name: Option<String>,
/// Assets directory path relatively to project path.
///
/// If specified more than one - all assets will be placed into one directory.
///
/// **Important:** This property has lower priority than Android or Apple `assets`
/// property.
pub assets: Option<PathBuf>,
#[serde(default)]
pub assets: Vec<PathBuf>,
/// Cross-platform permissions for Android and Apple.
///
/// **Important:** This property has lower priority than AndroidManifest or Apple
/// Info.plist properties.
#[serde(default)]
pub permissions: Vec<Permission>,
// TODO: Add `icon` field and icon generation.
// pub icon: Option<PathBuf>,
/// Cross-platform icon for Android and Apple.
///
/// All necessary icons will be automatically generated for Android and iOS.
pub icon: Option<PathBuf>,
#[cfg(feature = "android")]
#[serde(default)]
pub android: AndroidConfig,
Expand All @@ -43,12 +48,30 @@ pub struct CrossbowMetadata {

impl CrossbowMetadata {
#[cfg(feature = "android")]
pub fn get_android_assets(&self) -> Option<PathBuf> {
self.android.assets.clone().or_else(|| self.assets.clone())
pub fn get_android_assets(&self) -> &[PathBuf] {
if !self.android.assets.is_empty() {
&self.android.assets
} else {
&self.assets
}
}

#[cfg(feature = "apple")]
pub fn get_apple_assets(&self) -> &[PathBuf] {
if !self.apple.assets.is_empty() {
&self.apple.assets
} else {
&self.assets
}
}

#[cfg(feature = "android")]
pub fn get_android_resources(&self) -> &[PathBuf] {
&self.android.resources
}

#[cfg(feature = "apple")]
pub fn get_apple_assets(&self) -> Option<PathBuf> {
self.apple.assets.clone().or_else(|| self.assets.clone())
pub fn get_apple_resources(&self) -> &[PathBuf] {
&self.apple.resources
}
}
1 change: 1 addition & 0 deletions crossbundle/tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ which = "4.2"
tempfile = "3.3"
zip = "0.5"
zip-extensions = "0.6.1"
image = { version = "0.24.3", default-features = false, features = ["png", "jpeg"] }

itertools = "0.10"
cargo = "0.63.1"
Expand Down
Loading