--- name: signing-tauri-apps description: Guides the user through Tauri application code signing and notarization for Android, iOS, Linux, macOS, and Windows platforms including certificate setup and configuration. --- # Tauri Code Signing Skill This skill provides comprehensive guidance for code signing Tauri applications across all supported platforms. ## Platform Overview | Platform | Requirement | Certificate Type | |----------|-------------|------------------| | Android | Required for Play Store | Java Keystore (JKS) | | iOS | Required for distribution | Apple Developer Certificate | | Linux | Optional (enhances trust) | GPG Key | | macOS | Required for distribution | Developer ID / Apple Distribution | | Windows | Required (SmartScreen) | OV or EV Certificate | --- ## Android Signing ### Generate Keystore **macOS/Linux:** ```bash keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload ``` **Windows:** ```powershell keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias upload ``` ### Configuration File Create `src-tauri/gen/android/keystore.properties`: ```properties password= keyAlias=upload storeFile=/path/to/upload-keystore.jks ``` **IMPORTANT:** Never commit `keystore.properties` to version control. ### Gradle Configuration Modify `src-tauri/gen/android/app/build.gradle.kts`: ```kotlin import java.io.FileInputStream // Add before android { } block val keystorePropertiesFile = rootProject.file("keystore.properties") val keystoreProperties = java.util.Properties() if (keystorePropertiesFile.exists()) { keystoreProperties.load(FileInputStream(keystorePropertiesFile)) } android { // ... existing config ... signingConfigs { create("release") { keyAlias = keystoreProperties["keyAlias"] as String keyPassword = keystoreProperties["password"] as String storeFile = file(keystoreProperties["storeFile"] as String) storePassword = keystoreProperties["password"] as String } } buildTypes { release { signingConfig = signingConfigs.getByName("release") // ... other release config ... } } } ``` ### CI/CD Environment Variables | Variable | Description | |----------|-------------| | `ANDROID_KEY_ALIAS` | Key alias (e.g., `upload`) | | `ANDROID_KEY_PASSWORD` | Keystore password | | `ANDROID_KEY_BASE64` | Base64-encoded keystore file | **GitHub Actions Example:** ```yaml - name: Setup Android signing run: | cd src-tauri/gen/android echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties ``` --- ## iOS Signing ### Prerequisites - Apple Developer Program enrollment ($99/year) - Bundle identifier registered in App Store Connect - iOS code signing certificate - Mobile provisioning profile ### Automatic Signing (Recommended) For local development, authenticate through Xcode Settings > Accounts. For CI/CD, create an App Store Connect API key and set: | Variable | Description | |----------|-------------| | `APPLE_API_ISSUER` | Issuer ID from App Store Connect | | `APPLE_API_KEY` | Key ID from App Store Connect | | `APPLE_API_KEY_PATH` | Path to the `.p8` private key file | ### Manual Signing | Variable | Description | |----------|-------------| | `IOS_CERTIFICATE` | Base64-encoded `.p12` certificate | | `IOS_CERTIFICATE_PASSWORD` | Password used when exporting certificate | | `IOS_MOBILE_PROVISION` | Base64-encoded provisioning profile | ### Certificate Types by Distribution Method | Distribution | Certificate Type | |--------------|------------------| | Debugging | Apple Development or iOS App Development | | App Store | Apple Distribution or iOS Distribution | | Ad Hoc | Apple Distribution or iOS Distribution | ### Export Certificate 1. Open Keychain Access 2. Find your certificate 3. Right-click the private key 4. Select "Export" and save as `.p12` 5. Convert to base64: `base64 -i certificate.p12` ### Create Provisioning Profile 1. Register App ID with matching bundle identifier 2. Create provisioning profile for your distribution method 3. Link certificate to profile 4. Download and convert: `base64 -i profile.mobileprovision` --- ## Linux Signing (AppImage) ### Generate GPG Key ```bash gpg2 --full-gen-key ``` Back up the key securely. ### Environment Variables | Variable | Description | |----------|-------------| | `SIGN` | Set to `1` to enable signing | | `SIGN_KEY` | GPG Key ID (optional, uses default if not set) | | `APPIMAGETOOL_SIGN_PASSPHRASE` | Key password (required for CI/CD) | | `APPIMAGETOOL_FORCE_SIGN` | Set to `1` to fail build on signing error | ### Build with Signing ```bash SIGN=1 APPIMAGETOOL_SIGN_PASSPHRASE="your-passphrase" npm run tauri build ``` ### View Embedded Signature ```bash ./src-tauri/target/release/bundle/appimage/app_version_amd64.AppImage --appimage-signature ``` ### Validate Signature Download the validate tool from [AppImageUpdate releases](https://github.com/AppImageCommunity/AppImageUpdate/releases): ```bash chmod +x validate-x86_64.AppImage ./validate-x86_64.AppImage your-app.AppImage ``` **Note:** AppImage does not auto-validate signatures. Users must manually verify. --- ## macOS Signing and Notarization ### Prerequisites - Apple Developer Program enrollment ($99/year) - Mac computer for code signing - Free accounts cannot notarize applications ### Certificate Types | Certificate | Use Case | |-------------|----------| | Apple Distribution | App Store submissions | | Developer ID Application | Distribution outside App Store | ### Create Certificate 1. Generate Certificate Signing Request (CSR) from Keychain Access 2. Upload CSR at Apple Developer > Certificates, IDs & Profiles 3. Download and double-click `.cer` to install ### Configuration **tauri.conf.json:** ```json { "bundle": { "macOS": { "signingIdentity": "Developer ID Application: Your Name (TEAM_ID)" } } } ``` ### Environment Variables for CI/CD **Certificate Variables:** | Variable | Description | |----------|-------------| | `APPLE_CERTIFICATE` | Base64-encoded `.p12` certificate | | `APPLE_CERTIFICATE_PASSWORD` | Password for exported certificate | | `APPLE_SIGNING_IDENTITY` | Certificate name in keychain | **Notarization - Option 1: App Store Connect API (Recommended):** | Variable | Description | |----------|-------------| | `APPLE_API_ISSUER` | Issuer ID | | `APPLE_API_KEY` | Key ID | | `APPLE_API_KEY_PATH` | Path to `.p8` private key | **Notarization - Option 2: Apple ID:** | Variable | Description | |----------|-------------| | `APPLE_ID` | Apple ID email | | `APPLE_PASSWORD` | App-specific password | | `APPLE_TEAM_ID` | Team identifier | ### Export Certificate for CI/CD ```bash # Export from Keychain as .p12, then: base64 -i certificate.p12 | pbcopy ``` ### Ad-Hoc Signing (Testing Only) For unsigned distribution or testing without Apple credentials: ```json { "bundle": { "macOS": { "signingIdentity": "-" } } } ``` ### GitHub Actions Example ```yaml - name: Import certificate env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} run: | echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 security create-keychain -p actions temp.keychain security import certificate.p12 -k temp.keychain -P $APPLE_CERTIFICATE_PASSWORD -T /usr/bin/codesign security list-keychains -s temp.keychain security unlock-keychain -p actions temp.keychain security set-key-partition-list -S apple-tool:,apple: -s -k actions temp.keychain ``` --- ## Windows Signing ### Certificate Types | Type | SmartScreen | Availability | |------|-------------|--------------| | OV (Organization Validated) | Builds reputation over time | Before June 1, 2023 | | EV (Extended Validation) | Immediate trust | Required after June 1, 2023 | **Note:** Certificates obtained after June 1, 2023 require EV certificates for immediate SmartScreen trust. ### Configuration **tauri.conf.json:** ```json { "bundle": { "windows": { "certificateThumbprint": "A1B1A2B2A3B3A4B4A5B5A6B6A7B7A8B8A9B9A0B0", "digestAlgorithm": "sha256", "timestampUrl": "http://timestamp.sectigo.com" } } } ``` ### Find Certificate Thumbprint 1. Open certificate details 2. Go to Details tab 3. Find "Thumbprint" field 4. Copy the hex string (remove spaces) ### Common Timestamp URLs - `http://timestamp.sectigo.com` - `http://timestamp.digicert.com` - `http://timestamp.globalsign.com` ### Convert Certificate to PFX ```bash openssl pkcs12 -export -in cert.cer -inkey private-key.key -out certificate.pfx ``` ### Environment Variables for CI/CD | Variable | Description | |----------|-------------| | `WINDOWS_CERTIFICATE` | Base64-encoded `.pfx` file | | `WINDOWS_CERTIFICATE_PASSWORD` | PFX export password | ### GitHub Actions Example ```yaml - name: Import Windows certificate env: WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} run: | echo "$WINDOWS_CERTIFICATE" | base64 --decode > certificate.pfx Import-PfxCertificate -FilePath certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -AsPlainText -Force) shell: pwsh ``` ### Azure Key Vault Signing For cloud-based signing with Azure Key Vault: | Variable | Description | |----------|-------------| | `AZURE_CLIENT_ID` | Azure AD application client ID | | `AZURE_CLIENT_SECRET` | Azure AD application secret | | `AZURE_TENANT_ID` | Azure AD tenant ID | Configure in `tauri.conf.json`: ```json { "bundle": { "windows": { "signCommand": "relic sign --key azurekeyvault --file %1" } } } ``` ### Azure Trusted Signing For Azure Code Signing service: ```json { "bundle": { "windows": { "signCommand": "trusted-signing-cli -e -a -c %1" } } } ``` ### Custom Sign Command For other signing tools or cross-platform builds: ```json { "bundle": { "windows": { "signCommand": "your-signing-tool --sign %1" } } } ``` The `%1` placeholder is replaced with the executable path. --- ## Quick Reference: All Environment Variables ### Android - `ANDROID_KEY_ALIAS` - `ANDROID_KEY_PASSWORD` - `ANDROID_KEY_BASE64` ### iOS (Manual) - `IOS_CERTIFICATE` - `IOS_CERTIFICATE_PASSWORD` - `IOS_MOBILE_PROVISION` ### iOS/macOS (API Key) - `APPLE_API_ISSUER` - `APPLE_API_KEY` - `APPLE_API_KEY_PATH` ### macOS (Certificate) - `APPLE_CERTIFICATE` - `APPLE_CERTIFICATE_PASSWORD` - `APPLE_SIGNING_IDENTITY` ### macOS (Apple ID Notarization) - `APPLE_ID` - `APPLE_PASSWORD` - `APPLE_TEAM_ID` ### Linux - `SIGN` - `SIGN_KEY` - `APPIMAGETOOL_SIGN_PASSPHRASE` - `APPIMAGETOOL_FORCE_SIGN` ### Windows - `WINDOWS_CERTIFICATE` - `WINDOWS_CERTIFICATE_PASSWORD` ### Azure (Windows) - `AZURE_CLIENT_ID` - `AZURE_CLIENT_SECRET` - `AZURE_TENANT_ID`