返回 Skill 列表
extension
分类: 开发与工程无需 API Key

distributing-tauri-for-macos

引导用户在macOS上分发Tauri应用程序,包括创建DMG安装程序、配置应用程序包、设置权限以及自定义Info.plist文件以确保正确的macOS分发。

person作者: jakexiaohubgithub

Tauri macOS Distribution

This skill covers distributing Tauri v2 applications on macOS, including DMG installers and application bundle configuration.

Overview

macOS distribution for Tauri apps involves two primary formats:

  1. Application Bundle (.app) - The executable directory containing all app components
  2. DMG Installer (.dmg) - A disk image that wraps the app bundle for easy drag-and-drop installation

Building for macOS

Build Commands

Generate specific bundle types using the Tauri CLI:

# Build app bundle only
npm run tauri build -- --bundles app
yarn tauri build --bundles app
pnpm tauri build --bundles app
cargo tauri build --bundles app

# Build DMG installer only
npm run tauri build -- --bundles dmg
yarn tauri build --bundles dmg
pnpm tauri build --bundles dmg
cargo tauri build --bundles dmg

# Build both
npm run tauri build -- --bundles app,dmg

Application Bundle Structure

The .app directory follows macOS conventions:

<productName>.app/
Contents/
    Info.plist              # App metadata and configuration
    MacOS/
        <app-name>          # Main executable
    Resources/
        icon.icns           # App icon
        [bundled resources] # Additional resources
    _CodeSignature/         # Code signature files
    Frameworks/             # Bundled frameworks
    PlugIns/                # App plugins
    SharedSupport/          # Support files

DMG Installer Configuration

Configure DMG appearance in tauri.conf.json:

Complete DMG Configuration Example

{
  "bundle": {
    "macOS": {
      "dmg": {
        "background": "./images/dmg-background.png",
        "windowSize": {
          "width": 660,
          "height": 400
        },
        "windowPosition": {
          "x": 400,
          "y": 400
        },
        "appPosition": {
          "x": 180,
          "y": 220
        },
        "applicationFolderPosition": {
          "x": 480,
          "y": 220
        }
      }
    }
  }
}

DMG Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | background | string | - | Path to background image relative to src-tauri | | windowSize.width | number | 660 | DMG window width in pixels | | windowSize.height | number | 400 | DMG window height in pixels | | windowPosition.x | number | - | Initial window X position on screen | | windowPosition.y | number | - | Initial window Y position on screen | | appPosition.x | number | 180 | App icon X position in window | | appPosition.y | number | 220 | App icon Y position in window | | applicationFolderPosition.x | number | 480 | Applications folder X position | | applicationFolderPosition.y | number | 480 | Applications folder Y position |

Note: Icon sizes and positions may not apply correctly when building on CI/CD platforms due to a known issue with headless environments.

Info.plist Customization

Creating a Custom Info.plist

Create src-tauri/Info.plist to extend the default configuration. The Tauri CLI automatically merges this with generated values.

<?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>
    <!-- Privacy Usage Descriptions -->
    <key>NSCameraUsageDescription</key>
    <string>This app requires camera access for video calls</string>

    <key>NSMicrophoneUsageDescription</key>
    <string>This app requires microphone access for audio recording</string>

    <key>NSLocationUsageDescription</key>
    <string>This app requires location access for mapping features</string>

    <key>NSPhotoLibraryUsageDescription</key>
    <string>This app requires photo library access to import images</string>

    <!-- Document Types -->
    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeName</key>
            <string>My Document</string>
            <key>CFBundleTypeExtensions</key>
            <array>
                <string>mydoc</string>
            </array>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
        </dict>
    </array>

    <!-- URL Schemes -->
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>com.example.myapp</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myapp</string>
            </array>
        </dict>
    </array>
</dict>
</plist>

Common Info.plist Keys

| Key | Description | |-----|-------------| | NSCameraUsageDescription | Camera access explanation | | NSMicrophoneUsageDescription | Microphone access explanation | | NSLocationUsageDescription | Location access explanation | | NSPhotoLibraryUsageDescription | Photo library access explanation | | NSAppleEventsUsageDescription | AppleScript/automation access | | CFBundleDocumentTypes | Supported document types | | CFBundleURLTypes | Custom URL schemes | | LSMinimumSystemVersion | Minimum macOS version (prefer tauri.conf.json) |

Info.plist Localization

Support multiple languages with localized strings:

Directory structure:

src-tauri/
    infoplist/
        en.lproj/
            InfoPlist.strings
        de.lproj/
            InfoPlist.strings
        fr.lproj/
            InfoPlist.strings
        es.lproj/
            InfoPlist.strings

Example InfoPlist.strings (German):

"NSCameraUsageDescription" = "Diese App benötigt Kamerazugriff für Videoanrufe";
"NSMicrophoneUsageDescription" = "Diese App benötigt Mikrofonzugriff für Audioaufnahmen";

Configure in tauri.conf.json:

{
  "bundle": {
    "resources": {
      "infoplist/**": "./"
    }
  }
}

Entitlements Configuration

Entitlements grant special capabilities when your app is code-signed.

Creating Entitlements.plist

Create src-tauri/Entitlements.plist:

<?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>
    <!-- App Sandbox (required for App Store) -->
    <key>com.apple.security.app-sandbox</key>
    <true/>

    <!-- Network Access -->
    <key>com.apple.security.network.client</key>
    <true/>
    <key>com.apple.security.network.server</key>
    <true/>

    <!-- File Access -->
    <key>com.apple.security.files.user-selected.read-write</key>
    <true/>
    <key>com.apple.security.files.downloads.read-write</key>
    <true/>

    <!-- Hardware Access -->
    <key>com.apple.security.device.camera</key>
    <true/>
    <key>com.apple.security.device.microphone</key>
    <true/>

    <!-- Hardened Runtime -->
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
</dict>
</plist>

Configure Entitlements in tauri.conf.json

{
  "bundle": {
    "macOS": {
      "entitlements": "./Entitlements.plist"
    }
  }
}

Common Entitlements Reference

Sandbox Entitlements: | Entitlement | Description | |-------------|-------------| | com.apple.security.app-sandbox | Enable app sandbox (required for App Store) | | com.apple.security.network.client | Outbound network connections | | com.apple.security.network.server | Incoming network connections | | com.apple.security.files.user-selected.read-write | Access user-selected files | | com.apple.security.files.downloads.read-write | Access Downloads folder |

Hardware Entitlements: | Entitlement | Description | |-------------|-------------| | com.apple.security.device.camera | Camera access | | com.apple.security.device.microphone | Microphone access | | com.apple.security.device.usb | USB device access | | com.apple.security.device.bluetooth | Bluetooth access |

Hardened Runtime Entitlements: | Entitlement | Description | |-------------|-------------| | com.apple.security.cs.allow-jit | Allow JIT compilation | | com.apple.security.cs.allow-unsigned-executable-memory | Allow unsigned executable memory | | com.apple.security.cs.disable-library-validation | Load arbitrary plugins |

macOS Bundle Configuration

Complete macOS Configuration Example

{
  "bundle": {
    "icon": ["icons/icon.icns"],
    "macOS": {
      "minimumSystemVersion": "10.13",
      "entitlements": "./Entitlements.plist",
      "frameworks": [
        "CoreAudio",
        "./libs/libcustom.dylib",
        "./frameworks/CustomFramework.framework"
      ],
      "files": {
        "embedded.provisionprofile": "./profiles/distribution.provisionprofile",
        "SharedSupport/README.md": "./docs/README.md"
      },
      "dmg": {
        "background": "./images/dmg-background.png",
        "windowSize": {
          "width": 660,
          "height": 400
        },
        "appPosition": {
          "x": 180,
          "y": 220
        },
        "applicationFolderPosition": {
          "x": 480,
          "y": 220
        }
      }
    }
  }
}

Minimum System Version

Set the minimum supported macOS version:

{
  "bundle": {
    "macOS": {
      "minimumSystemVersion": "12.0"
    }
  }
}

Default: macOS 10.13 (High Sierra)

Including Frameworks and Libraries

Bundle system frameworks or custom dylib files:

{
  "bundle": {
    "macOS": {
      "frameworks": [
        "CoreAudio",
        "AVFoundation",
        "./libs/libmsodbcsql.18.dylib",
        "./frameworks/Sparkle.framework"
      ]
    }
  }
}
  • System frameworks: Specify name only (e.g., "CoreAudio")
  • Custom frameworks/dylibs: Provide path relative to src-tauri

Adding Custom Files to Bundle

Include additional files in the bundle's Contents directory:

{
  "bundle": {
    "macOS": {
      "files": {
        "embedded.provisionprofile": "./profile.provisionprofile",
        "SharedSupport/docs/guide.pdf": "./assets/guide.pdf",
        "Resources/config.json": "./config/default.json"
      }
    }
  }
}

Format: "destination": "source" where paths are relative to tauri.conf.json

Troubleshooting

Common Issues

DMG icons not positioned correctly on CI/CD:

  • This is a known issue with headless environments
  • Consider building DMGs locally or accepting default positioning

App rejected due to missing usage descriptions:

  • Add all required NS*UsageDescription keys to Info.plist
  • Ensure descriptions clearly explain why access is needed

Entitlements not applied:

  • Verify the entitlements file path in tauri.conf.json
  • Ensure the app is properly code-signed

Framework not found at runtime:

  • Check framework path is correct relative to src-tauri
  • Verify framework is properly signed

Verification Commands

# Check Info.plist contents
plutil -p path/to/App.app/Contents/Info.plist

# Verify entitlements
codesign -d --entitlements - path/to/App.app

# Check code signature
codesign -vvv --deep --strict path/to/App.app

# View bundle structure
find path/to/App.app -type f | head -50

Quick Reference

File Locations

| File | Location | Purpose | |------|----------|---------| | Info.plist | src-tauri/Info.plist | App metadata extensions | | Entitlements.plist | src-tauri/Entitlements.plist | Capability entitlements | | DMG Background | Any path in project | DMG window background | | Localized strings | src-tauri/infoplist/<lang>.lproj/ | Localized Info.plist values |

Build Output Locations

src-tauri/target/release/bundle/
    macos/
        <ProductName>.app         # Application bundle
    dmg/
        <ProductName>_<version>_<arch>.dmg  # DMG installer