mirror of
https://github.com/tauri-apps/tauri.git
synced 2025-01-05 01:42:35 +03:00
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
parent
2f8881c010
commit
dcdbe3eb6c
5
.changes/bundler-xattr.md
Normal file
5
.changes/bundler-xattr.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-bundler": patch:bug
|
||||
---
|
||||
|
||||
Remove extended attributes on the macOS app bundle using `xattr -cr $PATH`.
|
5
.changes/codesign-additional-files.md
Normal file
5
.changes/codesign-additional-files.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-bundler": patch:bug
|
||||
---
|
||||
|
||||
Code sign sidecars and frameworks on macOS.
|
@ -1 +0,0 @@
|
||||
Versions/Current/Headers
|
1
core/tests/app-updater/frameworks/test.framework/Headers
Symbolic link
1
core/tests/app-updater/frameworks/test.framework/Headers
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Headers
|
1
core/tests/app-updater/frameworks/test.framework/Modules
Symbolic link
1
core/tests/app-updater/frameworks/test.framework/Modules
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Modules
|
@ -1 +0,0 @@
|
||||
Versions/Current/Resources
|
1
core/tests/app-updater/frameworks/test.framework/Resources
Symbolic link
1
core/tests/app-updater/frameworks/test.framework/Resources
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Resources
|
@ -1 +1,18 @@
|
||||
// Testing that a header can be included
|
||||
//
|
||||
// test.h
|
||||
// test
|
||||
//
|
||||
// Created by Trey Smith on 9/15/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for test.
|
||||
FOUNDATION_EXPORT double testVersionNumber;
|
||||
|
||||
//! Project version string for test.
|
||||
FOUNDATION_EXPORT const unsigned char testVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <test/PublicHeader.h>
|
||||
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
framework module test {
|
||||
umbrella header "test.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
@ -2,12 +2,14 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>22D68</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>test</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.tauri.test.framework</string>
|
||||
<string>com.tauri.test</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@ -15,18 +17,30 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.15</string>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>NSPrincipalClass</key>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string></string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>macosx</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>13.3</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>22E245</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>macosx13.3</string>
|
||||
<key>DTXcode</key>
|
||||
<string>1431</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>14E300c</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>13.2</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -1 +0,0 @@
|
||||
Test that a LICENSE file can be included
|
@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>Resources/Info.plist</key>
|
||||
<data>
|
||||
/aPV7Q20g0elr7OiZJoUNggTOcg=
|
||||
</data>
|
||||
</dict>
|
||||
<key>files2</key>
|
||||
<dict>
|
||||
<key>Headers/test.h</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
5RA6Mnq5sNoaC4wKcFe6zymVmEL5Vb44G4BGqFjgZMM=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Modules/module.modulemap</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
C6uLLSnQu9M2qLElVCkeo2JpnvWMxtArinQzmlh3v2A=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Resources/Info.plist</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
nPMotNIMgvMfHtkRdpeehzfBiCZLnksfiD3nldUPzTE=
|
||||
</data>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^Resources/</key>
|
||||
<true/>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Resources/Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^[^/]+$</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
BIN
core/tests/app-updater/frameworks/test.framework/Versions/A/test
Normal file → Executable file
BIN
core/tests/app-updater/frameworks/test.framework/Versions/A/test
Normal file → Executable file
Binary file not shown.
@ -0,0 +1 @@
|
||||
A
|
@ -1 +0,0 @@
|
||||
Versions/Current
|
@ -318,12 +318,12 @@ fn update_app() {
|
||||
.first()
|
||||
.unwrap()
|
||||
.1
|
||||
.join("Contents/Frameworks/test.framework/test"),
|
||||
.join("Contents/Frameworks/test.framework/Modules"),
|
||||
)
|
||||
.expect("test.framework/test metadata");
|
||||
.expect("test.framework/Modules metadata");
|
||||
assert!(
|
||||
meta.file_type().is_symlink(),
|
||||
"test.framework/test should be a symlink"
|
||||
"test.framework/Modules should be a symlink"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,9 @@
|
||||
// files into the `Contents` directory of the bundle.
|
||||
|
||||
use super::{
|
||||
super::common,
|
||||
super::common::{self, CommandExt},
|
||||
icon::create_icns_file,
|
||||
sign::{notarize, notarize_auth, sign},
|
||||
sign::{notarize, notarize_auth, sign, SignTarget},
|
||||
};
|
||||
use crate::Settings;
|
||||
|
||||
@ -33,8 +33,10 @@ use anyhow::Context;
|
||||
use log::{info, warn};
|
||||
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
/// Bundles the project.
|
||||
@ -65,6 +67,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
|
||||
let resources_dir = bundle_directory.join("Resources");
|
||||
let bin_dir = bundle_directory.join("MacOS");
|
||||
let mut sign_paths = Vec::new();
|
||||
|
||||
let bundle_icon_file: Option<PathBuf> =
|
||||
{ create_icns_file(&resources_dir, settings).with_context(|| "Failed to create app icon")? };
|
||||
@ -72,20 +75,52 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
create_info_plist(&bundle_directory, bundle_icon_file, settings)
|
||||
.with_context(|| "Failed to create Info.plist")?;
|
||||
|
||||
copy_frameworks_to_bundle(&bundle_directory, settings)
|
||||
let framework_paths = copy_frameworks_to_bundle(&bundle_directory, settings)
|
||||
.with_context(|| "Failed to bundle frameworks")?;
|
||||
sign_paths.extend(
|
||||
framework_paths
|
||||
.into_iter()
|
||||
.filter(|p| {
|
||||
let ext = p.extension();
|
||||
ext == Some(OsStr::new("framework")) || ext == Some(OsStr::new("dylib"))
|
||||
})
|
||||
.map(|path| SignTarget {
|
||||
path,
|
||||
is_an_executable: false,
|
||||
}),
|
||||
);
|
||||
|
||||
settings.copy_resources(&resources_dir)?;
|
||||
|
||||
settings
|
||||
let bin_paths = settings
|
||||
.copy_binaries(&bin_dir)
|
||||
.with_context(|| "Failed to copy external binaries")?;
|
||||
sign_paths.extend(bin_paths.into_iter().map(|path| SignTarget {
|
||||
path,
|
||||
is_an_executable: true,
|
||||
}));
|
||||
|
||||
copy_binaries_to_bundle(&bundle_directory, settings)?;
|
||||
let bin_paths = copy_binaries_to_bundle(&bundle_directory, settings)?;
|
||||
sign_paths.extend(bin_paths.into_iter().map(|path| SignTarget {
|
||||
path,
|
||||
is_an_executable: true,
|
||||
}));
|
||||
|
||||
if let Some(identity) = &settings.macos().signing_identity {
|
||||
// Sign frameworks and sidecar binaries first, per apple, signing must be done inside out
|
||||
// https://developer.apple.com/forums/thread/701514
|
||||
sign_paths.push(SignTarget {
|
||||
path: app_bundle_path.clone(),
|
||||
is_an_executable: true,
|
||||
});
|
||||
|
||||
// Remove extra attributes, which could cause codesign to fail
|
||||
// https://developer.apple.com/library/archive/qa/qa1940/_index.html
|
||||
remove_extra_attr(&app_bundle_path)?;
|
||||
|
||||
// sign application
|
||||
sign(app_bundle_path.clone(), identity, settings, true)?;
|
||||
sign(sign_paths, identity, settings)?;
|
||||
|
||||
// notarization is required for distribution
|
||||
match notarize_auth() {
|
||||
Ok(auth) => {
|
||||
@ -100,15 +135,30 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
Ok(vec![app_bundle_path])
|
||||
}
|
||||
|
||||
fn remove_extra_attr(app_bundle_path: &Path) -> crate::Result<()> {
|
||||
Command::new("xattr")
|
||||
.arg("-cr")
|
||||
.arg(app_bundle_path)
|
||||
.output_ok()
|
||||
.context("failed to remove extra attributes from app bundle")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Copies the app's binaries to the bundle.
|
||||
fn copy_binaries_to_bundle(bundle_directory: &Path, settings: &Settings) -> crate::Result<()> {
|
||||
fn copy_binaries_to_bundle(
|
||||
bundle_directory: &Path,
|
||||
settings: &Settings,
|
||||
) -> crate::Result<Vec<PathBuf>> {
|
||||
let mut paths = Vec::new();
|
||||
let dest_dir = bundle_directory.join("MacOS");
|
||||
for bin in settings.binaries() {
|
||||
let bin_path = settings.binary_path(bin);
|
||||
common::copy_file(&bin_path, &dest_dir.join(bin.name()))
|
||||
let dest_path = dest_dir.join(bin.name());
|
||||
common::copy_file(&bin_path, &dest_path)
|
||||
.with_context(|| format!("Failed to copy binary from {:?}", bin_path))?;
|
||||
paths.push(dest_path);
|
||||
}
|
||||
Ok(())
|
||||
Ok(paths)
|
||||
}
|
||||
|
||||
// Creates the Info.plist file.
|
||||
@ -208,7 +258,12 @@ fn copy_framework_from(dest_dir: &Path, framework: &str, src_dir: &Path) -> crat
|
||||
}
|
||||
|
||||
// Copies the macOS application bundle frameworks to the .app
|
||||
fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> crate::Result<()> {
|
||||
fn copy_frameworks_to_bundle(
|
||||
bundle_directory: &Path,
|
||||
settings: &Settings,
|
||||
) -> crate::Result<Vec<PathBuf>> {
|
||||
let mut paths = Vec::new();
|
||||
|
||||
let frameworks = settings
|
||||
.macos()
|
||||
.frameworks
|
||||
@ -216,7 +271,7 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
if frameworks.is_empty() {
|
||||
return Ok(());
|
||||
return Ok(paths);
|
||||
}
|
||||
let dest_dir = bundle_directory.join("Frameworks");
|
||||
fs::create_dir_all(bundle_directory)
|
||||
@ -227,7 +282,9 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
|
||||
let src_name = src_path
|
||||
.file_name()
|
||||
.expect("Couldn't get framework filename");
|
||||
common::copy_dir(&src_path, &dest_dir.join(src_name))?;
|
||||
let dest_path = dest_dir.join(src_name);
|
||||
common::copy_dir(&src_path, &dest_path)?;
|
||||
paths.push(dest_path);
|
||||
continue;
|
||||
} else if framework.ends_with(".dylib") {
|
||||
let src_path = PathBuf::from(framework);
|
||||
@ -238,7 +295,9 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
|
||||
)));
|
||||
}
|
||||
let src_name = src_path.file_name().expect("Couldn't get library filename");
|
||||
common::copy_file(&src_path, &dest_dir.join(src_name))?;
|
||||
let dest_path = dest_dir.join(src_name);
|
||||
common::copy_file(&src_path, &dest_path)?;
|
||||
paths.push(dest_path);
|
||||
continue;
|
||||
} else if framework.contains('/') {
|
||||
return Err(crate::Error::GenericError(format!(
|
||||
@ -265,5 +324,5 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
|
||||
framework
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
Ok(paths)
|
||||
}
|
||||
|
@ -153,7 +153,14 @@ pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result<
|
||||
|
||||
// Sign DMG if needed
|
||||
if let Some(identity) = &settings.macos().signing_identity {
|
||||
super::sign::sign(dmg_path.clone(), identity, settings, false)?;
|
||||
super::sign::sign(
|
||||
vec![super::sign::SignTarget {
|
||||
path: dmg_path.clone(),
|
||||
is_an_executable: false,
|
||||
}],
|
||||
identity,
|
||||
settings,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(Bundled {
|
||||
|
@ -144,13 +144,13 @@ pub fn delete_keychain() {
|
||||
.output_ok();
|
||||
}
|
||||
|
||||
pub fn sign(
|
||||
path_to_sign: PathBuf,
|
||||
identity: &str,
|
||||
settings: &Settings,
|
||||
is_an_executable: bool,
|
||||
) -> crate::Result<()> {
|
||||
info!(action = "Signing"; "{} with identity \"{}\"", path_to_sign.display(), identity);
|
||||
pub struct SignTarget {
|
||||
pub path: PathBuf,
|
||||
pub is_an_executable: bool,
|
||||
}
|
||||
|
||||
pub fn sign(targets: Vec<SignTarget>, identity: &str, settings: &Settings) -> crate::Result<()> {
|
||||
info!(action = "Signing"; "with identity \"{}\"", identity);
|
||||
|
||||
let setup_keychain = if let (Some(certificate_encoded), Some(certificate_password)) = (
|
||||
var_os("APPLE_CERTIFICATE"),
|
||||
@ -164,20 +164,24 @@ pub fn sign(
|
||||
false
|
||||
};
|
||||
|
||||
let res = try_sign(
|
||||
path_to_sign,
|
||||
identity,
|
||||
settings,
|
||||
is_an_executable,
|
||||
setup_keychain,
|
||||
);
|
||||
info!("Signing app bundle...");
|
||||
|
||||
for target in targets {
|
||||
try_sign(
|
||||
target.path,
|
||||
identity,
|
||||
settings,
|
||||
target.is_an_executable,
|
||||
setup_keychain,
|
||||
)?;
|
||||
}
|
||||
|
||||
if setup_keychain {
|
||||
// delete the keychain again after signing
|
||||
delete_keychain();
|
||||
}
|
||||
|
||||
res
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_sign(
|
||||
@ -187,6 +191,8 @@ fn try_sign(
|
||||
is_an_executable: bool,
|
||||
tauri_keychain: bool,
|
||||
) -> crate::Result<()> {
|
||||
info!(action = "Signing"; "{}", path_to_sign.display());
|
||||
|
||||
let mut args = vec!["--force", "-s", identity];
|
||||
|
||||
if tauri_keychain {
|
||||
@ -205,13 +211,9 @@ fn try_sign(
|
||||
args.push("runtime");
|
||||
}
|
||||
|
||||
if path_to_sign.is_dir() {
|
||||
args.push("--deep");
|
||||
}
|
||||
|
||||
Command::new("codesign")
|
||||
.args(args)
|
||||
.arg(path_to_sign.to_string_lossy().to_string())
|
||||
.arg(path_to_sign)
|
||||
.output_ok()
|
||||
.context("failed to sign app")?;
|
||||
|
||||
@ -260,7 +262,14 @@ pub fn notarize(
|
||||
|
||||
// sign the zip file
|
||||
if let Some(identity) = &settings.macos().signing_identity {
|
||||
sign(zip_path.clone(), identity, settings, false)?;
|
||||
sign(
|
||||
vec![SignTarget {
|
||||
path: zip_path.clone(),
|
||||
is_an_executable: false,
|
||||
}],
|
||||
identity,
|
||||
settings,
|
||||
)?;
|
||||
};
|
||||
|
||||
let notarize_args = vec![
|
||||
|
@ -761,7 +761,11 @@ impl Settings {
|
||||
}
|
||||
|
||||
/// Copies external binaries to a path.
|
||||
pub fn copy_binaries(&self, path: &Path) -> crate::Result<()> {
|
||||
///
|
||||
/// Returns the list of destination paths.
|
||||
pub fn copy_binaries(&self, path: &Path) -> crate::Result<Vec<PathBuf>> {
|
||||
let mut paths = Vec::new();
|
||||
|
||||
for src in self.external_binaries() {
|
||||
let src = src?;
|
||||
let dest = path.join(
|
||||
@ -771,9 +775,10 @@ impl Settings {
|
||||
.to_string_lossy()
|
||||
.replace(&format!("-{}", self.target), ""),
|
||||
);
|
||||
common::copy_file(&src, dest)?;
|
||||
common::copy_file(&src, &dest)?;
|
||||
paths.push(dest);
|
||||
}
|
||||
Ok(())
|
||||
Ok(paths)
|
||||
}
|
||||
|
||||
/// Copies resources to a path.
|
||||
|
Loading…
Reference in New Issue
Block a user