cli/commands/build/
android.rs1use super::{BuildContext, SharedBuildCommand};
2use crate::error::*;
3use android_manifest::AndroidManifest;
4use clap::Clap;
5use creator_tools::{
6 commands::android,
7 tools::{AndroidNdk, AndroidSdk},
8 types::*,
9 utils::Config,
10};
11use std::path::PathBuf;
12
13#[derive(Clap, Clone, Debug)]
14pub struct AndroidBuildCommand {
15 #[clap(flatten)]
16 pub shared: SharedBuildCommand,
17 #[clap(long, default_value = "aarch64-linux-android")]
20 pub target: Vec<AndroidTarget>,
21 #[clap(long)]
23 pub sign_key_path: Option<PathBuf>,
24 #[clap(long)]
26 pub sign_key_pass: Option<String>,
27}
28
29impl AndroidBuildCommand {
30 pub fn run(&self, config: &Config) -> Result<()> {
31 if self.sign_key_path.is_some() && self.sign_key_pass.is_none() {
32 config
33 .shell()
34 .warn("You provided a signing key but not password - set password please by providing `sign_key_pass` flag")?;
35 }
36
37 let context = BuildContext::new(config, self.shared.target_dir.clone())?;
38 self.execute(config, &context)?;
39 Ok(())
40 }
41
42 pub fn execute(
43 &self,
44 config: &Config,
45 context: &BuildContext,
46 ) -> Result<(AndroidManifest, AndroidSdk, PathBuf)> {
47 let project_path = context.project_path.clone();
48 let target_dir = context.target_dir.clone();
49 let profile = self.shared.profile();
50 let (target, package_name) = if let Some(example) = &self.shared.example {
51 (Target::Example(example.clone()), example.clone())
52 } else {
53 (Target::Lib, context.package_name())
54 };
55 config.status_message("Starting build process", &package_name)?;
56 let sdk = AndroidSdk::from_env()?;
57 let ndk = AndroidNdk::from_env(Some(sdk.sdk_path()))?;
58 let build_targets = context.android_build_targets(&self.target);
59 let target_sdk_version = context.target_sdk_version(&sdk);
60 config.status_message("Generating", "AndroidManifest.xml")?;
61 let android_manifest =
62 context.gen_android_manifest(&sdk, &package_name, profile.is_debug())?;
63 let apk_build_dir = target_dir.join("android").join(&profile);
64 let manifest_path = android::save_android_manifest(&apk_build_dir, &android_manifest)?;
65 let mut compiled_libs = Vec::new();
66 for build_target in build_targets.iter() {
67 let lib_name = format!("lib{}.so", package_name.replace("-", "_"));
68 let rust_triple = build_target.rust_triple();
69 config.status_message("Compiling for architecture", rust_triple)?;
70 android::compile_rust_for_android(
71 &ndk,
72 target.clone(),
73 *build_target,
74 &project_path,
75 profile,
76 self.shared.features.clone(),
77 self.shared.all_features,
78 self.shared.no_default_features,
79 target_sdk_version,
80 )?;
81 let out_dir = target_dir.join(build_target.rust_triple()).join(&profile);
82 let compiled_lib = out_dir.join(lib_name);
83 compiled_libs.push((compiled_lib, build_target));
84 }
85 config.status_message("Generating", "unaligned APK file")?;
86 let unaligned_apk_path = android::gen_unaligned_apk(
87 &sdk,
88 &project_path,
89 &apk_build_dir,
90 &manifest_path,
91 context.android_assets(),
92 context.android_res(),
93 android_manifest
94 .application
95 .label
96 .clone()
97 .unwrap()
98 .to_string(),
99 target_sdk_version,
100 )?;
101 config.status("Adding libs into APK file")?;
102 for (compiled_lib, build_target) in compiled_libs {
103 android::add_libs_into_apk(
104 &sdk,
105 &ndk,
106 &unaligned_apk_path,
107 &compiled_lib,
108 *build_target,
109 profile,
110 android_manifest
111 .uses_sdk
112 .as_ref()
113 .unwrap()
114 .min_sdk_version
115 .unwrap_or(9),
116 &apk_build_dir,
117 &target_dir,
118 )?;
119 }
120 config.status("Aligning APK file")?;
121 let aligned_apk_path = android::align_apk(
122 &sdk,
123 &unaligned_apk_path,
124 &android_manifest
125 .application
126 .label
127 .clone()
128 .unwrap()
129 .to_string(),
130 &apk_build_dir,
131 )?;
132 let key = if let Some(path) = self.sign_key_path.clone() {
133 android::Key {
134 path,
135 password: self.sign_key_pass.clone().unwrap(),
136 }
137 } else {
138 config.status_message("Generating", "debug signing key")?;
139 android::gen_debug_key().unwrap()
140 };
141 config.status("Signing APK file")?;
142 android::sign_apk(&sdk, &aligned_apk_path, key).unwrap();
143 config.status("Build finished successfully")?;
144 Ok((android_manifest, sdk, aligned_apk_path))
145 }
146}