diff --git a/.changes/fix-fileassociations-missing-lshandlerrank-on-macos.md b/.changes/fix-fileassociations-missing-lshandlerrank-on-macos.md new file mode 100644 index 000000000..2348775ed --- /dev/null +++ b/.changes/fix-fileassociations-missing-lshandlerrank-on-macos.md @@ -0,0 +1,8 @@ +--- +"tauri-bundler": "patch:bug" +"tauri-utils": "patch:bug" +"tauri-cli": "patch:bug" +"@tauri-apps/cli": "patch:bug" +--- + +Fix `fileAssociations` missing `LSHandlerRank` on macOS. diff --git a/crates/tauri-bundler/src/bundle/macos/app.rs b/crates/tauri-bundler/src/bundle/macos/app.rs index 213ad4f36..bcc504c97 100644 --- a/crates/tauri-bundler/src/bundle/macos/app.rs +++ b/crates/tauri-bundler/src/bundle/macos/app.rs @@ -271,6 +271,7 @@ fn create_info_plist( "CFBundleTypeRole".into(), association.role.to_string().into(), ); + dict.insert("LSHandlerRank".into(), association.rank.to_string().into()); plist::Value::Dictionary(dict) }) .collect(), diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index d80ff823c..1fdee5ef0 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -2345,6 +2345,15 @@ "string", "null" ] + }, + "rank": { + "description": "The ranking of this app among apps that declare themselves as editors or viewers of the given file type. Maps to `LSHandlerRank` on macOS.", + "default": "Default", + "allOf": [ + { + "$ref": "#/definitions/HandlerRank" + } + ] } }, "additionalProperties": false @@ -2393,6 +2402,39 @@ } ] }, + "HandlerRank": { + "description": "Corresponds to LSHandlerRank", + "oneOf": [ + { + "description": "LSHandlerRank.Default. This app is an opener of files of this type; this value is also used if no rank is specified.", + "type": "string", + "enum": [ + "Default" + ] + }, + { + "description": "LSHandlerRank.Owner. This app is the primary creator of files of this type.", + "type": "string", + "enum": [ + "Owner" + ] + }, + { + "description": "LSHandlerRank.Alternate. This app is a secondary viewer of files of this type.", + "type": "string", + "enum": [ + "Alternate" + ] + }, + { + "description": "LSHandlerRank.None. This app is never selected to open files of this type, but it accepts drops of files of this type.", + "type": "string", + "enum": [ + "None" + ] + } + ] + }, "WindowsConfig": { "description": "Windows bundler configuration.\n\n See more: ", "type": "object", diff --git a/crates/tauri-cli/schema.json b/crates/tauri-cli/schema.json index 52e20429b..1edc55e78 100644 --- a/crates/tauri-cli/schema.json +++ b/crates/tauri-cli/schema.json @@ -1966,6 +1966,15 @@ "string", "null" ] + }, + "rank": { + "description": "The ranking of this app among apps that declare themselves as editors or viewers of the given file type. Maps to `LSHandlerRank` on macOS.", + "default": "Default", + "allOf": [ + { + "$ref": "#/definitions/HandlerRank" + } + ] } }, "additionalProperties": false @@ -2014,6 +2023,39 @@ } ] }, + "HandlerRank": { + "description": "Corresponds to LSHandlerRank", + "oneOf": [ + { + "description": "LSHandlerRank.Default. This app is an opener of files of this type; this value is also used if no rank is specified.", + "type": "string", + "enum": [ + "Default" + ] + }, + { + "description": "LSHandlerRank.Owner. This app is the primary creator of files of this type.", + "type": "string", + "enum": [ + "Owner" + ] + }, + { + "description": "LSHandlerRank.Alternate. This app is a secondary viewer of files of this type.", + "type": "string", + "enum": [ + "Alternate" + ] + }, + { + "description": "LSHandlerRank.None. This app is never selected to open files of this type, but it accepts drops of files of this type.", + "type": "string", + "enum": [ + "None" + ] + } + ] + }, "WindowsConfig": { "description": "Windows bundler configuration.\n\n See more: ", "type": "object", diff --git a/crates/tauri-cli/tauri.config.schema.json b/crates/tauri-cli/tauri.config.schema.json index 52e20429b..1edc55e78 100644 --- a/crates/tauri-cli/tauri.config.schema.json +++ b/crates/tauri-cli/tauri.config.schema.json @@ -1966,6 +1966,15 @@ "string", "null" ] + }, + "rank": { + "description": "The ranking of this app among apps that declare themselves as editors or viewers of the given file type. Maps to `LSHandlerRank` on macOS.", + "default": "Default", + "allOf": [ + { + "$ref": "#/definitions/HandlerRank" + } + ] } }, "additionalProperties": false @@ -2014,6 +2023,39 @@ } ] }, + "HandlerRank": { + "description": "Corresponds to LSHandlerRank", + "oneOf": [ + { + "description": "LSHandlerRank.Default. This app is an opener of files of this type; this value is also used if no rank is specified.", + "type": "string", + "enum": [ + "Default" + ] + }, + { + "description": "LSHandlerRank.Owner. This app is the primary creator of files of this type.", + "type": "string", + "enum": [ + "Owner" + ] + }, + { + "description": "LSHandlerRank.Alternate. This app is a secondary viewer of files of this type.", + "type": "string", + "enum": [ + "Alternate" + ] + }, + { + "description": "LSHandlerRank.None. This app is never selected to open files of this type, but it accepts drops of files of this type.", + "type": "string", + "enum": [ + "None" + ] + } + ] + }, "WindowsConfig": { "description": "Windows bundler configuration.\n\n See more: ", "type": "object", diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index d80ff823c..1fdee5ef0 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -2345,6 +2345,15 @@ "string", "null" ] + }, + "rank": { + "description": "The ranking of this app among apps that declare themselves as editors or viewers of the given file type. Maps to `LSHandlerRank` on macOS.", + "default": "Default", + "allOf": [ + { + "$ref": "#/definitions/HandlerRank" + } + ] } }, "additionalProperties": false @@ -2393,6 +2402,39 @@ } ] }, + "HandlerRank": { + "description": "Corresponds to LSHandlerRank", + "oneOf": [ + { + "description": "LSHandlerRank.Default. This app is an opener of files of this type; this value is also used if no rank is specified.", + "type": "string", + "enum": [ + "Default" + ] + }, + { + "description": "LSHandlerRank.Owner. This app is the primary creator of files of this type.", + "type": "string", + "enum": [ + "Owner" + ] + }, + { + "description": "LSHandlerRank.Alternate. This app is a secondary viewer of files of this type.", + "type": "string", + "enum": [ + "Alternate" + ] + }, + { + "description": "LSHandlerRank.None. This app is never selected to open files of this type, but it accepts drops of files of this type.", + "type": "string", + "enum": [ + "None" + ] + } + ] + }, "WindowsConfig": { "description": "Windows bundler configuration.\n\n See more: ", "type": "object", diff --git a/crates/tauri-utils/src/config.rs b/crates/tauri-utils/src/config.rs index ac18901f7..6c93e37a8 100644 --- a/crates/tauri-utils/src/config.rs +++ b/crates/tauri-utils/src/config.rs @@ -1090,6 +1090,34 @@ impl Display for BundleTypeRole { } } +// Issue #13159 - Missing the LSHandlerRank and Apple warns after uploading to App Store Connect. +// https://github.com/tauri-apps/tauri/issues/13159 +/// Corresponds to LSHandlerRank +#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] +pub enum HandlerRank { + /// LSHandlerRank.Default. This app is an opener of files of this type; this value is also used if no rank is specified. + #[default] + Default, + /// LSHandlerRank.Owner. This app is the primary creator of files of this type. + Owner, + /// LSHandlerRank.Alternate. This app is a secondary viewer of files of this type. + Alternate, + /// LSHandlerRank.None. This app is never selected to open files of this type, but it accepts drops of files of this type. + None, +} + +impl Display for HandlerRank { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => write!(f, "Default"), + Self::Owner => write!(f, "Owner"), + Self::Alternate => write!(f, "Alternate"), + Self::None => write!(f, "None"), + } + } +} + /// An extension for a [`FileAssociation`]. /// /// A leading `.` is automatically stripped. @@ -1131,6 +1159,9 @@ pub struct FileAssociation { /// The mime-type e.g. 'image/png' or 'text/plain'. Linux-only. #[serde(alias = "mime-type")] pub mime_type: Option, + /// The ranking of this app among apps that declare themselves as editors or viewers of the given file type. Maps to `LSHandlerRank` on macOS. + #[serde(default)] + pub rank: HandlerRank, } /// Deep link protocol configuration. diff --git a/examples/file-associations/package.json b/examples/file-associations/package.json index 767a7c0f3..a920e2156 100644 --- a/examples/file-associations/package.json +++ b/examples/file-associations/package.json @@ -7,7 +7,7 @@ ] }, "scripts": { - "tauri": "node ../../packages/cli/node/tauri.js" + "tauri": "node ../../packages/cli/tauri.js" }, "devDependencies": {} } diff --git a/examples/file-associations/src-tauri/tauri.conf.json b/examples/file-associations/src-tauri/tauri.conf.json index 88848b309..3ac3be0fd 100644 --- a/examples/file-associations/src-tauri/tauri.conf.json +++ b/examples/file-associations/src-tauri/tauri.conf.json @@ -22,15 +22,18 @@ "fileAssociations": [ { "ext": ["png"], - "mimeType": "image/png" + "mimeType": "image/png", + "rank": "Default" }, { "ext": ["jpg", "jpeg"], - "mimeType": "image/jpeg" + "mimeType": "image/jpeg", + "rank": "Alternate" }, { "ext": ["gif"], - "mimeType": "image/gif" + "mimeType": "image/gif", + "rank": "Owner" } ] }