mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-01-31 00:35:19 +01:00
feat: bundle type detection at runtime via binary patching (#13209)
* patch binary with bundle type info * only patch if the updater is included * fix linux warnings * patch binary when updaer is configured * patch binary with bundle type info only patch if the updater is included fix linux warnings patch binary when updaer is configured * fix formatting * fix license header * fix taplo error * move __TAURI_BUNDLE_TYPE to utils * export get_current_bundle_type * macos fix * cleanup, add api * update change file * fix windows * fmt, fix rust version support * fix macos --------- Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
5
.changes/app-bundle-type.md
Normal file
5
.changes/app-bundle-type.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@tauri-apps/api": patch:feat
|
||||||
|
---
|
||||||
|
|
||||||
|
Added `getBundleType` to the app module.
|
||||||
5
.changes/patch-binaries.md
Normal file
5
.changes/patch-binaries.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
tauri-cli: patch:enhance
|
||||||
|
---
|
||||||
|
|
||||||
|
Binaries are patched before bundling to add the type of a bundle they will placed in. This information will be used during update process to select the correct target.
|
||||||
5
.changes/platform-bundle-type.md
Normal file
5
.changes/platform-bundle-type.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"tauri-utils": patch:feat
|
||||||
|
---
|
||||||
|
|
||||||
|
Added `platform::bundle_type`.
|
||||||
109
.gitignore
vendored
109
.gitignore
vendored
@@ -1,54 +1,55 @@
|
|||||||
# dependency directories
|
# dependency directories
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
# Optional npm and yarn cache directory
|
# Optional npm and yarn cache directory
|
||||||
.npm/
|
.npm/
|
||||||
.yarn/
|
.yarn/
|
||||||
|
|
||||||
# Output of 'npm pack'
|
# Output of 'npm pack'
|
||||||
*.tgz
|
*.tgz
|
||||||
|
|
||||||
# dotenv environment variables file
|
# dotenv environment variables file
|
||||||
.env
|
.env
|
||||||
|
|
||||||
# .vscode workspace settings file
|
# .vscode workspace settings file
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/tasks.json
|
.vscode/tasks.json
|
||||||
|
|
||||||
# npm, yarn and bun lock files
|
# npm, yarn and bun lock files
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
bun.lockb
|
bun.lockb
|
||||||
|
|
||||||
# rust compiled folders
|
# rust compiled folders
|
||||||
target/
|
target/
|
||||||
|
|
||||||
# test video for streaming example
|
# test video for streaming example
|
||||||
streaming_example_test_video.mp4
|
streaming_example_test_video.mp4
|
||||||
|
|
||||||
# examples /gen directory
|
# examples /gen directory
|
||||||
/examples/**/src-tauri/gen/
|
/examples/**/src-tauri/gen/
|
||||||
/bench/**/src-tauri/gen/
|
/bench/**/src-tauri/gen/
|
||||||
|
|
||||||
# logs
|
# logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
# runtime data
|
# runtime data
|
||||||
pids
|
pids
|
||||||
*.pid
|
*.pid
|
||||||
*.seed
|
*.seed
|
||||||
*.pid.lock
|
*.pid.lock
|
||||||
|
|
||||||
# miscellaneous
|
# miscellaneous
|
||||||
/.vs
|
/.vs
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.Thumbs.db
|
.Thumbs.db
|
||||||
*.sublime*
|
*.sublime*
|
||||||
.idea
|
.idea
|
||||||
debug.log
|
debug.log
|
||||||
TODO.md
|
TODO.md
|
||||||
|
.aider*
|
||||||
|
|||||||
14
Cargo.lock
generated
14
Cargo.lock
generated
@@ -277,7 +277,7 @@ dependencies = [
|
|||||||
"figment",
|
"figment",
|
||||||
"filetime",
|
"filetime",
|
||||||
"glob",
|
"glob",
|
||||||
"goblin",
|
"goblin 0.8.2",
|
||||||
"hex",
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
"md-5",
|
"md-5",
|
||||||
@@ -2980,6 +2980,17 @@ dependencies = [
|
|||||||
"scroll",
|
"scroll",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "goblin"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "daa0a64d21a7eb230583b4c5f4e23b7e4e57974f96620f42a7e75e08ae66d745"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"plain",
|
||||||
|
"scroll",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "group"
|
name = "group"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
@@ -8459,6 +8470,7 @@ dependencies = [
|
|||||||
"dunce",
|
"dunce",
|
||||||
"flate2",
|
"flate2",
|
||||||
"glob",
|
"glob",
|
||||||
|
"goblin 0.9.3",
|
||||||
"handlebars",
|
"handlebars",
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"hex",
|
"hex",
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ dunce = "1"
|
|||||||
url = "2"
|
url = "2"
|
||||||
uuid = { version = "1", features = ["v4", "v5"] }
|
uuid = { version = "1", features = ["v4", "v5"] }
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
goblin = "0.9"
|
||||||
|
|
||||||
[target."cfg(target_os = \"windows\")".dependencies]
|
[target."cfg(target_os = \"windows\")".dependencies]
|
||||||
bitness = "0.4"
|
bitness = "0.4"
|
||||||
|
|||||||
@@ -15,6 +15,32 @@ mod windows;
|
|||||||
|
|
||||||
use tauri_utils::{display_path, platform::Target as TargetPlatform};
|
use tauri_utils::{display_path, platform::Target as TargetPlatform};
|
||||||
|
|
||||||
|
/// Patch a binary with bundle type information
|
||||||
|
fn patch_binary(binary: &PathBuf, package_type: &PackageType) -> crate::Result<()> {
|
||||||
|
match package_type {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
PackageType::AppImage | PackageType::Deb | PackageType::Rpm => {
|
||||||
|
log::info!(
|
||||||
|
"Patching binary {:?} for type {}",
|
||||||
|
binary,
|
||||||
|
package_type.short_name()
|
||||||
|
);
|
||||||
|
linux::patch_binary(binary, package_type)?;
|
||||||
|
}
|
||||||
|
PackageType::Nsis | PackageType::WindowsMsi => {
|
||||||
|
log::info!(
|
||||||
|
"Patching binary {:?} for type {}",
|
||||||
|
binary,
|
||||||
|
package_type.short_name()
|
||||||
|
);
|
||||||
|
windows::patch_binary(binary, package_type)?;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
category::AppCategory,
|
category::AppCategory,
|
||||||
settings::{
|
settings::{
|
||||||
@@ -87,6 +113,12 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let main_binary = settings
|
||||||
|
.binaries()
|
||||||
|
.iter()
|
||||||
|
.find(|b| b.main())
|
||||||
|
.expect("Main binary missing in settings");
|
||||||
|
|
||||||
let mut bundles = Vec::<Bundle>::new();
|
let mut bundles = Vec::<Bundle>::new();
|
||||||
for package_type in &package_types {
|
for package_type in &package_types {
|
||||||
// bundle was already built! e.g. DMG already built .app
|
// bundle was already built! e.g. DMG already built .app
|
||||||
@@ -94,6 +126,8 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
patch_binary(&settings.binary_path(main_binary), package_type)?;
|
||||||
|
|
||||||
let bundle_paths = match package_type {
|
let bundle_paths = match package_type {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
PackageType::MacOsBundle => macos::app::bundle_project(settings)?,
|
PackageType::MacOsBundle => macos::app::bundle_project(settings)?,
|
||||||
|
|||||||
@@ -7,3 +7,8 @@ pub mod appimage;
|
|||||||
pub mod debian;
|
pub mod debian;
|
||||||
pub mod freedesktop;
|
pub mod freedesktop;
|
||||||
pub mod rpm;
|
pub mod rpm;
|
||||||
|
|
||||||
|
mod util;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub use util::patch_binary;
|
||||||
|
|||||||
59
crates/tauri-bundler/src/bundle/linux/util.rs
Normal file
59
crates/tauri-bundler/src/bundle/linux/util.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
/// Change value of __TAURI_BUNDLE_TYPE static variable to mark which package type it was bundled in
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn patch_binary(
|
||||||
|
binary_path: &std::path::PathBuf,
|
||||||
|
package_type: &crate::PackageType,
|
||||||
|
) -> crate::Result<()> {
|
||||||
|
let mut file_data = std::fs::read(binary_path).expect("Could not read binary file.");
|
||||||
|
|
||||||
|
let elf = match goblin::Object::parse(&file_data)? {
|
||||||
|
goblin::Object::Elf(elf) => elf,
|
||||||
|
_ => return Err(crate::Error::GenericError("Not an ELF file".to_owned())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let offset = find_bundle_type_symbol(elf).ok_or(crate::Error::MissingBundleTypeVar)?;
|
||||||
|
let offset = offset as usize;
|
||||||
|
if offset + 3 <= file_data.len() {
|
||||||
|
let chars = &mut file_data[offset..offset + 3];
|
||||||
|
match package_type {
|
||||||
|
crate::PackageType::Deb => chars.copy_from_slice(b"DEB"),
|
||||||
|
crate::PackageType::Rpm => chars.copy_from_slice(b"RPM"),
|
||||||
|
crate::PackageType::AppImage => chars.copy_from_slice(b"APP"),
|
||||||
|
_ => {
|
||||||
|
return Err(crate::Error::InvalidPackageType(
|
||||||
|
package_type.short_name().to_owned(),
|
||||||
|
"linux".to_owned(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::write(binary_path, &file_data)
|
||||||
|
.map_err(|error| crate::Error::BinaryWriteError(error.to_string()))?;
|
||||||
|
} else {
|
||||||
|
return Err(crate::Error::BinaryOffsetOutOfRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find address of a symbol in relocations table
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn find_bundle_type_symbol(elf: goblin::elf::Elf<'_>) -> Option<i64> {
|
||||||
|
for sym in elf.syms.iter() {
|
||||||
|
if let Some(name) = elf.strtab.get_at(sym.st_name) {
|
||||||
|
if name == "__TAURI_BUNDLE_TYPE" {
|
||||||
|
for reloc in elf.dynrelas.iter() {
|
||||||
|
if reloc.r_offset == sym.st_value {
|
||||||
|
return Some(reloc.r_addend.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub mod msi;
|
pub mod msi;
|
||||||
|
|
||||||
pub mod nsis;
|
pub mod nsis;
|
||||||
pub mod sign;
|
pub mod sign;
|
||||||
|
|
||||||
@@ -13,3 +14,5 @@ pub use util::{
|
|||||||
NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, WIX_OUTPUT_FOLDER_NAME,
|
NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, WIX_OUTPUT_FOLDER_NAME,
|
||||||
WIX_UPDATER_OUTPUT_FOLDER_NAME,
|
WIX_UPDATER_OUTPUT_FOLDER_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use util::patch_binary;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use std::{
|
|||||||
fs::create_dir_all,
|
fs::create_dir_all,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ureq::ResponseExt;
|
use ureq::ResponseExt;
|
||||||
|
|
||||||
use crate::utils::http_utils::download;
|
use crate::utils::http_utils::download;
|
||||||
@@ -84,3 +83,77 @@ pub fn os_bitness<'a>() -> Option<&'a str> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn patch_binary(binary_path: &PathBuf, package_type: &crate::PackageType) -> crate::Result<()> {
|
||||||
|
let file_data = std::fs::read(binary_path)?;
|
||||||
|
let mut file_data = file_data; // make mutable
|
||||||
|
|
||||||
|
let pe = match goblin::Object::parse(&file_data)? {
|
||||||
|
goblin::Object::PE(pe) => pe,
|
||||||
|
_ => {
|
||||||
|
return Err(crate::Error::BinaryParseError(
|
||||||
|
std::io::Error::new(std::io::ErrorKind::InvalidInput, "binary is not a PE file").into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let tauri_bundle_section = pe
|
||||||
|
.sections
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.name().unwrap_or_default() == ".taubndl")
|
||||||
|
.ok_or(crate::Error::MissingBundleTypeVar)?;
|
||||||
|
|
||||||
|
let data_offset = tauri_bundle_section.pointer_to_raw_data as usize;
|
||||||
|
|
||||||
|
if data_offset + 8 > file_data.len() {
|
||||||
|
return Err(crate::Error::BinaryOffsetOutOfRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr_bytes = &file_data[data_offset..data_offset + 8];
|
||||||
|
let ptr_value = u64::from_le_bytes(ptr_bytes.try_into().map_err(|_| {
|
||||||
|
crate::Error::BinaryParseError(
|
||||||
|
std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid pointer bytes").into(),
|
||||||
|
)
|
||||||
|
})?);
|
||||||
|
|
||||||
|
let rdata_section = pe
|
||||||
|
.sections
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.name().unwrap_or_default() == ".rdata")
|
||||||
|
.ok_or_else(|| {
|
||||||
|
crate::Error::BinaryParseError(
|
||||||
|
std::io::Error::new(std::io::ErrorKind::InvalidInput, ".rdata section not found").into(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let rva = ptr_value.checked_sub(pe.image_base as u64).ok_or_else(|| {
|
||||||
|
crate::Error::BinaryParseError(
|
||||||
|
std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid RVA offset").into(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let file_offset = rdata_section.pointer_to_raw_data as usize
|
||||||
|
+ (rva as usize).saturating_sub(rdata_section.virtual_address as usize);
|
||||||
|
|
||||||
|
if file_offset + 3 > file_data.len() {
|
||||||
|
return Err(crate::Error::BinaryOffsetOutOfRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite the string at that offset
|
||||||
|
let string_bytes = &mut file_data[file_offset..file_offset + 3];
|
||||||
|
match package_type {
|
||||||
|
crate::PackageType::Nsis => string_bytes.copy_from_slice(b"NSS"),
|
||||||
|
crate::PackageType::WindowsMsi => string_bytes.copy_from_slice(b"MSI"),
|
||||||
|
_ => {
|
||||||
|
return Err(crate::Error::InvalidPackageType(
|
||||||
|
package_type.short_name().to_owned(),
|
||||||
|
"windows".to_owned(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::write(binary_path, &file_data)
|
||||||
|
.map_err(|e| crate::Error::BinaryWriteError(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,6 +64,21 @@ pub enum Error {
|
|||||||
/// Failed to validate downloaded file hash.
|
/// Failed to validate downloaded file hash.
|
||||||
#[error("hash mismatch of downloaded file")]
|
#[error("hash mismatch of downloaded file")]
|
||||||
HashError,
|
HashError,
|
||||||
|
/// Failed to parse binary
|
||||||
|
#[error("Binary parse error: `{0}`")]
|
||||||
|
BinaryParseError(#[from] goblin::error::Error),
|
||||||
|
/// Package type is not supported by target platform
|
||||||
|
#[error("Wrong package type {0} for platform {1}")]
|
||||||
|
InvalidPackageType(String, String),
|
||||||
|
/// Bundle type symbol missing in binary
|
||||||
|
#[error("__TAURI_BUNDLE_TYPE variable not found in binary. Make sure tauri crate and tauri-cli are up to date")]
|
||||||
|
MissingBundleTypeVar,
|
||||||
|
/// Failed to write binary file changed
|
||||||
|
#[error("Failed to write binary file changes: `{0}`")]
|
||||||
|
BinaryWriteError(String),
|
||||||
|
/// Invalid offset while patching binary file
|
||||||
|
#[error("Invalid offset while patching binary file")]
|
||||||
|
BinaryOffsetOutOfRange,
|
||||||
/// Unsupported architecture.
|
/// Unsupported architecture.
|
||||||
#[error("Architecture Error: `{0}`")]
|
#[error("Architecture Error: `{0}`")]
|
||||||
ArchError(String),
|
ArchError(String),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::{fmt::Display, path::PathBuf};
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Env, PackageInfo};
|
use crate::{config::BundleType, Env, PackageInfo};
|
||||||
|
|
||||||
mod starting_binary;
|
mod starting_binary;
|
||||||
|
|
||||||
@@ -345,6 +345,32 @@ fn resource_dir_from<P: AsRef<std::path::Path>>(
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Variable holding the type of bundle the executable is stored in. This is modified by binary
|
||||||
|
// patching during build
|
||||||
|
#[no_mangle]
|
||||||
|
#[cfg_attr(not(target_vendor = "apple"), link_section = ".taubndl")]
|
||||||
|
#[cfg_attr(target_vendor = "apple", link_section = "__DATA,taubndl")]
|
||||||
|
static __TAURI_BUNDLE_TYPE: &str = "UNK";
|
||||||
|
|
||||||
|
/// Get the type of the bundle current binary is packaged in.
|
||||||
|
/// If the bundle type is unknown, it returns [`Option::None`].
|
||||||
|
pub fn bundle_type() -> Option<BundleType> {
|
||||||
|
match __TAURI_BUNDLE_TYPE {
|
||||||
|
"DEB" => Some(BundleType::Deb),
|
||||||
|
"RPM" => Some(BundleType::Rpm),
|
||||||
|
"APP" => Some(BundleType::AppImage),
|
||||||
|
"MSI" => Some(BundleType::Msi),
|
||||||
|
"NSS" => Some(BundleType::Nsis),
|
||||||
|
_ => {
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
Some(BundleType::App)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "build")]
|
#[cfg(feature = "build")]
|
||||||
mod build {
|
mod build {
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
|
|||||||
("default_window_icon", false),
|
("default_window_icon", false),
|
||||||
("set_app_theme", false),
|
("set_app_theme", false),
|
||||||
("set_dock_visibility", false),
|
("set_dock_visibility", false),
|
||||||
|
("bundle_type", true),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ Default permissions for the plugin.
|
|||||||
- `allow-name`
|
- `allow-name`
|
||||||
- `allow-tauri-version`
|
- `allow-tauri-version`
|
||||||
- `allow-identifier`
|
- `allow-identifier`
|
||||||
|
- `allow-bundle-type`
|
||||||
|
|
||||||
## Permission Table
|
## Permission Table
|
||||||
|
|
||||||
@@ -73,6 +74,32 @@ Denies the app_show command without any pre-configured scope.
|
|||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
|
`core:app:allow-bundle-type`
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Enables the bundle_type command without any pre-configured scope.
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
`core:app:deny-bundle-type`
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Denies the bundle_type command without any pre-configured scope.
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
`core:app:allow-default-window-icon`
|
`core:app:allow-default-window-icon`
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use tauri_utils::Theme;
|
use tauri_utils::{config::BundleType, Theme};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
command,
|
command,
|
||||||
@@ -110,6 +110,11 @@ pub async fn set_dock_visibility<R: Runtime>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[command(root = "crate")]
|
||||||
|
pub fn bundle_type() -> Option<BundleType> {
|
||||||
|
tauri_utils::platform::bundle_type()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||||
Builder::new("app")
|
Builder::new("app")
|
||||||
.invoke_handler(crate::generate_handler![
|
.invoke_handler(crate::generate_handler![
|
||||||
@@ -125,6 +130,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
default_window_icon,
|
default_window_icon,
|
||||||
set_app_theme,
|
set_app_theme,
|
||||||
set_dock_visibility,
|
set_dock_visibility,
|
||||||
|
bundle_type,
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
<script>
|
<script>
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { getName, getVersion, getTauriVersion } from '@tauri-apps/api/app'
|
import {
|
||||||
|
getName,
|
||||||
|
getVersion,
|
||||||
|
getTauriVersion,
|
||||||
|
getBundleType
|
||||||
|
} from '@tauri-apps/api/app'
|
||||||
|
|
||||||
let { onMessage } = $props()
|
let { onMessage } = $props()
|
||||||
|
|
||||||
let version = $state('1.0.0')
|
let version = $state('1.0.0')
|
||||||
let tauriVersion = $state('1.0.0')
|
let tauriVersion = $state('1.0.0')
|
||||||
let appName = $state('Unknown')
|
let appName = $state('Unknown')
|
||||||
|
let bundleType = $state('Unknown')
|
||||||
|
|
||||||
getName().then((n) => {
|
getName().then((n) => {
|
||||||
appName = n
|
appName = n
|
||||||
@@ -17,6 +23,11 @@
|
|||||||
getTauriVersion().then((v) => {
|
getTauriVersion().then((v) => {
|
||||||
tauriVersion = v
|
tauriVersion = v
|
||||||
})
|
})
|
||||||
|
getBundleType().then((b) => {
|
||||||
|
if (b) {
|
||||||
|
bundleType = b
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function contextMenu() {
|
function contextMenu() {
|
||||||
invoke('plugin:app-menu|popup')
|
invoke('plugin:app-menu|popup')
|
||||||
@@ -34,7 +45,9 @@
|
|||||||
<pre>
|
<pre>
|
||||||
App name: <code>{appName}</code>
|
App name: <code>{appName}</code>
|
||||||
App version: <code>{version}</code>
|
App version: <code>{version}</code>
|
||||||
Tauri version: <code>{tauriVersion}</code></pre>
|
Tauri version: <code>{tauriVersion}</code>
|
||||||
|
Bundle type: <code>{bundleType}</code>
|
||||||
|
</pre>
|
||||||
|
|
||||||
<button class="btn" onclick={contextMenu}>Context menu</button>
|
<button class="btn" onclick={contextMenu}>Context menu</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,6 +25,24 @@ export type DataStoreIdentifier = [
|
|||||||
number
|
number
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundle type of the current application.
|
||||||
|
*/
|
||||||
|
export enum BundleType {
|
||||||
|
/** Windows NSIS */
|
||||||
|
Nsis = 'nsis',
|
||||||
|
/** Windows MSI */
|
||||||
|
Msi = 'msi',
|
||||||
|
/** Linux Debian package */
|
||||||
|
Deb = 'deb',
|
||||||
|
/** Linux RPM */
|
||||||
|
Rpm = 'rpm',
|
||||||
|
/** Linux AppImage */
|
||||||
|
AppImage = 'appimage',
|
||||||
|
/** macOS app bundle */
|
||||||
|
App = 'app'
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application metadata and related APIs.
|
* Application metadata and related APIs.
|
||||||
*
|
*
|
||||||
@@ -206,6 +224,10 @@ async function setDockVisibility(visible: boolean): Promise<void> {
|
|||||||
return invoke('plugin:app|set_dock_visibility', { visible })
|
return invoke('plugin:app|set_dock_visibility', { visible })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getBundleType(): Promise<BundleType> {
|
||||||
|
return invoke('plugin:app|bundle_type')
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getName,
|
getName,
|
||||||
getVersion,
|
getVersion,
|
||||||
@@ -217,5 +239,6 @@ export {
|
|||||||
setTheme,
|
setTheme,
|
||||||
fetchDataStoreIdentifiers,
|
fetchDataStoreIdentifiers,
|
||||||
removeDataStore,
|
removeDataStore,
|
||||||
setDockVisibility
|
setDockVisibility,
|
||||||
|
getBundleType
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user