Skip to content

Commit fac4a4a

Browse files
committed
feat: Support Android release flavors (feat #504) #505
We now allow the `run_with_application_id_suffix` command for Android. This allows for the running of different build variants (such as debug and release), as described in [these docs](https://developer.android.com/build/build-variants#build-types). This is related to the Tauri feature described [here](tauri-apps/tauri#14777).
1 parent c77b28d commit fac4a4a

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

.changes/android-build-variants.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"cargo-mobile2": minor
3+
---
4+
5+
# Android build variants
6+
7+
In order to support running different build variants (such as debug and
8+
release), we now support calling `Device::run_with_application_id_suffix`.
9+
10+
This relates to the `applicationIdSuffix` as defined in Android development,
11+
described [in these docs](https://developer.android.com/build/build-variants#build-types).

src/android/cli.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ pub enum Command {
7676
help = "Specifies which activtiy to launch"
7777
)]
7878
activity: Option<String>,
79+
#[structopt(
80+
long = "application-id-suffix",
81+
help = "Optional suffix for the application ID (e.g. \".debug\")"
82+
)]
83+
application_id_suffix: Option<String>,
7984
},
8085
#[structopt(name = "st", about = "Displays a detailed stacktrace for a device")]
8186
Stacktrace,
@@ -301,12 +306,13 @@ impl Exec for Input {
301306
filter: cli::Filter { filter },
302307
reinstall_deps: cli::ReinstallDeps { reinstall_deps },
303308
activity,
309+
application_id_suffix,
304310
} => with_config(non_interactive, wrapper, |config, metadata, env| {
305311
let build_app_bundle = metadata.asset_packs().is_some();
306312
ensure_init(config)?;
307313
device_prompt(env)
308314
.map_err(Error::DevicePromptFailed)?
309-
.run(
315+
.run_with_application_id_suffix(
310316
config,
311317
env,
312318
noise_level,
@@ -320,6 +326,7 @@ impl Exec for Input {
320326
.unwrap_or(DEFAULT_ACTIVITY)
321327
.to_string()
322328
}),
329+
application_id_suffix,
323330
)
324331
.and_then(|h| {
325332
h.wait().map(|_| ()).map_err(|err| RunError::CommandFailed {

src/android/device.rs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,12 @@ impl<'a> Device<'a> {
370370
Ok(())
371371
}
372372

373+
/**
374+
* This is the legacy function that doesn't support applicationIdSuffix, which
375+
* is required for running different build variants (such as debug and release).
376+
*
377+
* It is kept for backwards compatibility.
378+
*/
373379
#[allow(clippy::too_many_arguments)]
374380
pub fn run(
375381
&self,
@@ -381,6 +387,32 @@ impl<'a> Device<'a> {
381387
build_app_bundle: bool,
382388
reinstall_deps: bool,
383389
activity: String,
390+
) -> Result<duct::Handle, RunError> {
391+
return self.run_with_application_id_suffix(
392+
config,
393+
env,
394+
noise_level,
395+
profile,
396+
filter_level,
397+
build_app_bundle,
398+
reinstall_deps,
399+
activity,
400+
None
401+
);
402+
}
403+
404+
#[allow(clippy::too_many_arguments)]
405+
pub fn run_with_application_id_suffix(
406+
&self,
407+
config: &Config,
408+
env: &Env,
409+
noise_level: NoiseLevel,
410+
profile: Profile,
411+
filter_level: Option<FilterLevel>,
412+
build_app_bundle: bool,
413+
reinstall_deps: bool,
414+
activity: String,
415+
application_id_suffix: Option<String>,
384416
) -> Result<duct::Handle, RunError> {
385417
if build_app_bundle {
386418
bundletool::install(reinstall_deps).map_err(RunError::BundletoolInstallFailed)?;
@@ -402,7 +434,8 @@ impl<'a> Device<'a> {
402434
self.install_apk(config, env, profile)
403435
.map_err(RunError::ApkInstallFailed)?;
404436
}
405-
let activity = format!("{}/{}", config.app().identifier(), activity);
437+
438+
let activity = Device::resolve_activity_name(config.app().identifier().to_string(), application_id_suffix, activity);
406439
let activity_ = activity.clone();
407440
let cmd = self
408441
.adb(env)
@@ -518,4 +551,44 @@ impl<'a> Device<'a> {
518551
}
519552
Ok(())
520553
}
554+
555+
/**
556+
* The activity name is the fully qualified class name of the activity to launch.
557+
* Here are the expected formats for the activity name: of the release and debug variants
558+
*
559+
* Release variants have 2 acceptable formats:
560+
* * `com.example.app/.MainActivity`
561+
* * `com.example.app/com.example.app.MainActivity`
562+
*
563+
* Debug variants have 1 acceptable format:
564+
* * `com.example.app.debug/com.example.app.MainActivity`
565+
*/
566+
fn resolve_activity_name(
567+
app_identifier: String,
568+
application_id_suffix: Option<String>,
569+
activity: String,
570+
) -> String {
571+
let identifier: String = match application_id_suffix {
572+
Some(suffix) => format!("{}{}", app_identifier, suffix),
573+
None => app_identifier,
574+
};
575+
576+
return format!("{}/{}", identifier, activity);
577+
}
521578
}
579+
580+
#[cfg(test)]
581+
mod test {
582+
use rstest::rstest;
583+
use super::*;
584+
#[rstest(
585+
app_identifier, application_id_suffix, activity, expected,
586+
case("com.example.app", Some(".debug"), "com.example.app.MainActivity", "com.example.app.debug/com.example.app.MainActivity"),
587+
case("com.example.app", None, ".MainActivity", "com.example.app/.MainActivity"),
588+
case("com.example.app", None, "com.example.app.MainActivity", "com.example.app/com.example.app.MainActivity"),
589+
)]
590+
fn test_resolve_activity_name(app_identifier: String, application_id_suffix: Option<&str>, activity: String, expected: String) {
591+
let activity = Device::resolve_activity_name(app_identifier, application_id_suffix.map(|s| s.to_string()), activity);
592+
assert_eq!(activity, expected);
593+
}
594+
}

0 commit comments

Comments
 (0)