fix(cli, breaking): Align Android applicationId with user's bundle.identifier (#4103)
* fix(cli, breaking): Align Android applicationId with user's `bundle.identifier`
This commit fixes the Android `applicationId` generation to accurately reflect the user-configured `bundle.identifier` when provided. It also refactors the logic by removing the `full_mobile_app_name` function, with `bundle_identifier` now being the direct source for the Android `applicationId`.
The `bundle_identifier` function now operates as follows:
1. If `bundle.identifier` is explicitly set by the user:
- It validates that the identifier has at least three segments (e.g., `com.example.app`).
- The user's `identifier` is then returned and used directly as the Android `applicationId`.
2. If `config.bundle.identifier` is not set by the user:
- It defaults to `com.example.{PascalCaseExecutableName}`. The `executable_name` (e.g., "my-app" derived from a project name like "MyApp") is converted to `PascalCase` (e.g., "MyApp") for this default.
**BREAKING CHANGE**:
This change primarily affects Android builds and may alter the final `applicationId` for users who had a custom `bundle.identifier` set, particularly if its casing or final segment differed from the PascalCased `executable_name`.
- **Previous Behavior**:
The Android `applicationId` was derived from `full_mobile_app_name`. This function effectively used the first two segments of the `bundle_identifier` (user-configured or default) but then **always** appended a PascalCased version of the `executable_name` as the final segment.
Example Scenario:
- User project name: "MyApp" (CLI set `executable_name` to "my-app")
- User configured `bundle.identifier` in Dioxus config: `"com.custom.myapp"`
- `bundled_app_name()` (from "my-app"): "MyApp"
- Old `applicationId` (via `full_mobile_app_name`): `"com.custom.MyApp"`
- **New Behavior**:
With the same user configuration (`"com.custom.myapp"`), the `applicationId` will now be: `"com.custom.myapp"`
This change ensures the `applicationId` respects the user's explicit `bundle.identifier` string. However, if users were unknowingly relying on the previous behavior where the last segment was always a PascalCased version of the `executable_name` (potentially mismatching their intended lowercase final segment in `bundle.identifier`), their `applicationId` will change upon updating the CLI.
According to Google's Android documentation, the `applicationId` must not be changed after an app is published, as this causes Google Play to treat it as a new application. Users who have published Android apps and utilized custom `bundle.identifier` configurations should meticulously verify their `applicationId` after this update to ensure it remains consistent with their published versions or to take appropriate action if a change is detected.
* fix: relax validation for bundle.identifier
1. Contains at least one dot ('.').
2. Does not start with a dot.
3. Does not end with a dot.
4. Does not contain consecutive dots ('..').
e.g., `com.example` or `com.example.app`
---------
Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
1 parent
2be2333ef4
commit
bfb0642a1d
2 files changed
+17
-21
No files matched your search
@@ -1180,7 +1180,7 @@ We checked the folder: {}
|
||||
) -> Result<()> {
|
||||
let apk_path = self.build.debug_apk_path();
|
||||
let session_cache = self.build.session_cache_dir();
|
||||
let full_mobile_app_name = self.build.full_mobile_app_name();
|
||||
let application_id = self.build.bundle_identifier();
|
||||
let adb = self.build.workspace.android_tools()?.adb.clone();
|
||||
|
||||
// Start backgrounded since .open() is called while in the arm of the top-level match
|
||||
@@ -1261,7 +1261,7 @@ We checked the folder: {}
|
||||
|
||||
// eventually, use the user's MainActivity, not our MainActivity
|
||||
// adb shell am start -n dev.dioxus.main/dev.dioxus.main.MainActivity
|
||||
let activity_name = format!("{}/dev.dioxus.main.MainActivity", full_mobile_app_name,);
|
||||
let activity_name = format!("{application_id}/dev.dioxus.main.MainActivity");
|
||||
let res = Command::new(&adb)
|
||||
.arg("shell")
|
||||
.arg("am")
|
||||
|
||||
@@ -2567,7 +2567,7 @@ impl BuildRequest {
|
||||
android_bundle: Option<crate::AndroidSettings>,
|
||||
}
|
||||
let hbs_data = AndroidHandlebarsObjects {
|
||||
application_id: self.full_mobile_app_name(),
|
||||
application_id: self.bundle_identifier(),
|
||||
app_name: self.bundled_app_name(),
|
||||
android_bundle: self.config.bundle.android.clone(),
|
||||
};
|
||||
@@ -2979,30 +2979,26 @@ impl BuildRequest {
|
||||
kept_features
|
||||
}
|
||||
|
||||
pub(crate) fn mobile_org(&self) -> String {
|
||||
let identifier = self.bundle_identifier();
|
||||
let mut split = identifier.splitn(3, '.');
|
||||
let sub = split
|
||||
.next()
|
||||
.expect("Identifier to have at least 3 periods like `com.example.app`");
|
||||
let tld = split
|
||||
.next()
|
||||
.expect("Identifier to have at least 3 periods like `com.example.app`");
|
||||
format!("{}.{}", sub, tld)
|
||||
}
|
||||
|
||||
pub(crate) fn bundled_app_name(&self) -> String {
|
||||
use convert_case::{Case, Casing};
|
||||
self.executable_name().to_case(Case::Pascal)
|
||||
}
|
||||
|
||||
pub(crate) fn full_mobile_app_name(&self) -> String {
|
||||
format!("{}.{}", self.mobile_org(), self.bundled_app_name())
|
||||
}
|
||||
|
||||
pub(crate) fn bundle_identifier(&self) -> String {
|
||||
if let Some(identifier) = self.config.bundle.identifier.clone() {
|
||||
return identifier.clone();
|
||||
if let Some(identifier) = &self.config.bundle.identifier {
|
||||
if identifier.contains('.')
|
||||
&& !identifier.starts_with('.')
|
||||
&& !identifier.ends_with('.')
|
||||
&& !identifier.contains("..")
|
||||
{
|
||||
return identifier.clone();
|
||||
} else {
|
||||
// The original `mobile_org` function used `expect` directly.
|
||||
// Maybe it's acceptable for the CLI to panic directly when this error occurs.
|
||||
// And if we change it to a Result type, the `client_connected` function in serve/runner.rs does not return a Result and cannot call `?`,
|
||||
// We also need to handle the error in place, otherwise it will expand the scope of modifications further.
|
||||
panic!("Invalid bundle identifier: {identifier:?}. E.g. `com.example`, `com.example.app`");
|
||||
}
|
||||
}
|
||||
|
||||
format!("com.example.{}", self.bundled_app_name())
|
||||
|
||||
Reference in new issue
Block a user