From 5c9eceda0bf802fd3ecf91410af6b01e37159c24 Mon Sep 17 00:00:00 2001 From: Tamerlan Satualdypov Date: Sat, 20 Apr 2024 23:40:53 +0500 Subject: [PATCH] feature: Sparkle (#61) --- .github/release-drafter.yml | 14 ++-- .github/workflows/create-new-version.yml | 8 +- .github/workflows/create-release-draft.yml | 11 ++- .github/workflows/package.yml | 44 ++++++++--- .github/workflows/release.yml | 2 +- mupl.xcodeproj/project.pbxproj | 29 +++++++ .../Components/AppInfo/AppInfoView.swift | 79 +++++++++++++------ .../Extensions/UI/View + Tappable.swift | 4 +- .../Services/AppUpdater/AppUpdater.swift | 37 +++++++++ mupl/Supporting Files/App/AppDelegate.swift | 5 +- mupl/Supporting Files/Resources/Info.plist | 8 ++ .../Resources/mupl.entitlements | 5 ++ 12 files changed, 197 insertions(+), 49 deletions(-) create mode 100644 mupl/Common/Models/Services/AppUpdater/AppUpdater.swift diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 2ab12fb..1dbf1ea 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -6,7 +6,9 @@ categories: label: 'bug' - title: '🧰 Maintenance' collapse-after: 5 - label: 'chore' + labels: + - 'chore' + - 'doc' change-template: '- $TITLE by @$AUTHOR (#$NUMBER)' autolabeler: - label: 'feature' @@ -15,16 +17,18 @@ autolabeler: - label: 'bug' branch: - '/fix.+/i' + - label: 'chore' + branch: + - '/chore.+/i' + - '/doc.+/i' replacers: - search: '/(feature:|bug:)\s*/i' replace: '' exclude-labels: - "release" header: | - -
-
+ template: | - ## What's new? + # What's new? $CHANGES \ No newline at end of file diff --git a/.github/workflows/create-new-version.yml b/.github/workflows/create-new-version.yml index edc4be6..b6740c5 100644 --- a/.github/workflows/create-new-version.yml +++ b/.github/workflows/create-new-version.yml @@ -15,11 +15,14 @@ jobs: - name: Set Version run: | + xcrun agvtool new-version -all ${{ github.ref_name }} xcrun agvtool new-marketing-version ${{ github.ref_name }} echo "APP_VERSION=${{ github.ref_name }}" >> $GITHUB_ENV - name: Create Pull Request uses: peter-evans/create-pull-request@v6 + env: + APP_VERSION: ${{ env.APP_VERSION }} with: token: ${{ secrets.GITHUB_TOKEN }} title: | @@ -32,6 +35,5 @@ jobs: branch: release/${{ env.APP_VERSION }} labels: release author: GitHub Action - committer: GitHub Action - delete-branch: true - signoff: true \ No newline at end of file + reviewers: onl1ner + delete-branch: true \ No newline at end of file diff --git a/.github/workflows/create-release-draft.yml b/.github/workflows/create-release-draft.yml index f29390e..187706b 100644 --- a/.github/workflows/create-release-draft.yml +++ b/.github/workflows/create-release-draft.yml @@ -15,7 +15,8 @@ jobs: - name: Download DMG uses: actions/download-artifact@v3 with: - name: mupl + name: mupl-archive + path: mupl-archive - name: Prepare Release uses: marvinpinto/action-automatic-releases@latest @@ -23,9 +24,13 @@ jobs: repo_token: ${{ secrets.GITHUB_TOKEN }} draft: true automatic_release_tag: ${{ inputs.tag }} - files: mupl.dmg + files: | + mupl-archive/mupl.dmg + mupl-archive/appcast.xml - name: Generate Release Notes uses: release-drafter/release-drafter@v5 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag: ${{ inputs.tag }} \ No newline at end of file diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 6e8682e..b0f8f34 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -3,19 +3,19 @@ name: 'Package' on: workflow_call: outputs: - version: + app_version: description: "The version of packaged application" - value: ${{ jobs.release.outputs.version }} + value: ${{ jobs.release.outputs.app_version }} jobs: release: runs-on: [macos-14] outputs: - version: ${{ steps.output.outputs.VERSION }} + app_version: ${{ steps.output.outputs.APP_VERSION }} steps: - name: Checkout repository uses: actions/checkout@v3 - + - name: Install tools run: | brew install create-dmg @@ -44,20 +44,25 @@ jobs: security import $DEV_ID_P12 -P "$DEV_ID_CERT_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH - + + - name: Get application version + run: | + echo "APP_VERSION=$(xcrun agvtool mvers -terse1)" >> $GITHUB_ENV + - name: Build application env: DEV_TEAM_ID: ${{ secrets.DEV_TEAM_ID }} run: | - xcodebuild -scheme mupl -configuration Release -archivePath "$RUNNER_TEMP/mupl.xcarchive" DEVELOPMENT_TEAM=$DEV_TEAM_ID archive + xcodebuild -scheme mupl -configuration Release -derivedDataPath "$RUNNER_TEMP/DerivedData" -archivePath "$RUNNER_TEMP/mupl.xcarchive" DEVELOPMENT_TEAM=$DEV_TEAM_ID archive - name: Sign application env: CODESIGN_ID: ${{ secrets.CODESIGN_ID }} run: | codesign -s "$CODESIGN_ID" -f --timestamp -o runtime "$RUNNER_TEMP/mupl.xcarchive/Products/Applications/mupl.app/Contents/Frameworks/Lottie.framework" + codesign -s "$CODESIGN_ID" -f --timestamp -o runtime --deep "$RUNNER_TEMP/mupl.xcarchive/Products/Applications/mupl.app/Contents/Frameworks/Sparkle.framework" codesign -s "$CODESIGN_ID" -f --timestamp -o runtime "$RUNNER_TEMP/mupl.xcarchive/Products/Applications/mupl.app" - + - name: Create DMG env: CODESIGN_ID: ${{ secrets.CODESIGN_ID }} @@ -79,13 +84,32 @@ jobs: "$RUNNER_TEMP/mupl.dmg" \ "$RUNNER_TEMP/mupl.xcarchive/Products/Applications/" + - name: Update AppCast + env: + APP_VERSION: ${{ env.APP_VERSION }} + SPARKLE_KEY: ${{ secrets.SPARKLE_KEY }} + run: | + SPARKLE_BIN="$RUNNER_TEMP/DerivedData/SourcePackages/artifacts/sparkle/Sparkle/bin" + SPARKLE_ARCHIVE="$RUNNER_TEMP/Archive" + SPARKLE_LINK="https://github.com/mupl-app/mupl-macos" + SPARKLE_DOWNLOAD_PREFIX="https://github.com/mupl-app/mupl-macos/releases/download" + + echo "$SPARKLE_KEY" > "$RUNNER_TEMP/sparkle-key" + + mkdir "$SPARKLE_ARCHIVE" + cp "$RUNNER_TEMP/mupl.dmg" "$SPARKLE_ARCHIVE" + + "$SPARKLE_BIN/generate_appcast" --ed-key-file "$RUNNER_TEMP/sparkle_key" --download-url-prefix "$SPARKLE_DOWNLOAD_PREFIX/${{ env.APP_VERSION }}/" --link "$SPARKLE_LINK" "$SPARKLE_ARCHIVE" + - name: Upload DMG uses: actions/upload-artifact@v3 with: - name: mupl - path: ${{ runner.temp }}/mupl.dmg + name: mupl-archive + path: ${{ runner.temp }}/Archive - id: output name: Output version + env: + APP_VERSION: ${{ env.APP_VERSION }} run: | - echo "VERSION=$(xcrun agvtool mvers -terse1)" >> $GITHUB_OUTPUT \ No newline at end of file + echo "APP_VERSION=${{ env.APP_VERSION }}" >> $GITHUB_OUTPUT \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ee2fc42..4d1d85f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,5 +29,5 @@ jobs: name: Draft Release uses: ./.github/workflows/create-release-draft.yml with: - tag: ${{ needs.package.outputs.version }} + tag: ${{ needs.package.outputs.app_version }} secrets: inherit \ No newline at end of file diff --git a/mupl.xcodeproj/project.pbxproj b/mupl.xcodeproj/project.pbxproj index f1bc5ee..8297325 100644 --- a/mupl.xcodeproj/project.pbxproj +++ b/mupl.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 08415D0A2B3F550A00764CD6 /* View + Tappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08415D092B3F550A00764CD6 /* View + Tappable.swift */; }; 08415D0C2B3F5D4700764CD6 /* Color + Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08415D0B2B3F5D4700764CD6 /* Color + Palette.swift */; }; 08415D142B40BA6600764CD6 /* QueueBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08415D132B40BA6600764CD6 /* QueueBar.swift */; }; + 084AA2612BC7E1F900CD152B /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 084AA2602BC7E1F900CD152B /* Sparkle */; }; 084E07BD2B8CBA4B00E14695 /* Chips.swift in Sources */ = {isa = PBXBuildFile; fileRef = 084E07BC2B8CBA4B00E14695 /* Chips.swift */; }; 084E07BF2B8CBF2900E14695 /* LibraryTrackCollectionList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 084E07BE2B8CBF2900E14695 /* LibraryTrackCollectionList.swift */; }; 084E07C62B8DC25300E14695 /* Artist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 084E07C52B8DC25300E14695 /* Artist.swift */; }; @@ -109,6 +110,7 @@ 08D1B6072B765700005FB6FA /* PlaylistDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08D1B6062B765700005FB6FA /* PlaylistDetailsView.swift */; }; 08D1B60A2B76576E005FB6FA /* PlaylistDetailsInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08D1B6092B76576E005FB6FA /* PlaylistDetailsInfoView.swift */; }; 08D1B60C2B765E02005FB6FA /* PlaylistDetailsTrackList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08D1B60B2B765E02005FB6FA /* PlaylistDetailsTrackList.swift */; }; + 08D57CA22BD129910053E015 /* AppUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08D57CA12BD129910053E015 /* AppUpdater.swift */; }; 08F4230E2B45AC10005158F2 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F4230D2B45AC10005158F2 /* Network.swift */; }; 08F423122B45AC60005158F2 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F423112B45AC60005158F2 /* Endpoint.swift */; }; 08F423152B45AC85005158F2 /* Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F423142B45AC85005158F2 /* Encodable.swift */; }; @@ -231,6 +233,7 @@ 08D1B6062B765700005FB6FA /* PlaylistDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistDetailsView.swift; sourceTree = ""; }; 08D1B6092B76576E005FB6FA /* PlaylistDetailsInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistDetailsInfoView.swift; sourceTree = ""; }; 08D1B60B2B765E02005FB6FA /* PlaylistDetailsTrackList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistDetailsTrackList.swift; sourceTree = ""; }; + 08D57CA12BD129910053E015 /* AppUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdater.swift; sourceTree = ""; }; 08F4230D2B45AC10005158F2 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 08F423112B45AC60005158F2 /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = ""; }; 08F423142B45AC85005158F2 /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = ""; }; @@ -254,6 +257,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 084AA2612BC7E1F900CD152B /* Sparkle in Frameworks */, 0856A4F92B4B2F3D0073ACE7 /* SDWebImageSwiftUI in Frameworks */, 082683F62B8796D6007108E9 /* Lottie in Frameworks */, ); @@ -546,6 +550,7 @@ 0856A4B22B46D58B0073ACE7 /* Services */ = { isa = PBXGroup; children = ( + 08D57CA02BD129830053E015 /* AppUpdater */, 0856A4B12B46D5870073ACE7 /* Music */, 08F4230C2B45AC09005158F2 /* Network */, ); @@ -992,6 +997,14 @@ path = Components; sourceTree = ""; }; + 08D57CA02BD129830053E015 /* AppUpdater */ = { + isa = PBXGroup; + children = ( + 08D57CA12BD129910053E015 /* AppUpdater.swift */, + ); + path = AppUpdater; + sourceTree = ""; + }; 08F4230C2B45AC09005158F2 /* Network */ = { isa = PBXGroup; children = ( @@ -1110,6 +1123,7 @@ packageProductDependencies = ( 0856A4F82B4B2F3D0073ACE7 /* SDWebImageSwiftUI */, 082683F52B8796D6007108E9 /* Lottie */, + 084AA2602BC7E1F900CD152B /* Sparkle */, ); productName = mupl; productReference = 08B77F412B20F9D2004B6D8D /* mupl.app */; @@ -1142,6 +1156,7 @@ packageReferences = ( 0856A4F72B4B2F3D0073ACE7 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */, 082683F42B8796D6007108E9 /* XCRemoteSwiftPackageReference "lottie-spm" */, + 084AA25F2BC7E1F900CD152B /* XCRemoteSwiftPackageReference "Sparkle" */, ); productRefGroup = 08B77F422B20F9D2004B6D8D /* Products */; projectDirPath = ""; @@ -1205,6 +1220,7 @@ 0856A4B52B46E0D90073ACE7 /* MusicManager.swift in Sources */, 08F4231D2B45B27B005158F2 /* Data.swift in Sources */, 08415CFB2B3DC1FA00764CD6 /* Slider.swift in Sources */, + 08D57CA22BD129910053E015 /* AppUpdater.swift in Sources */, 086FDBA02B7E645200A4102E /* ArtistDetailsPlaylistsSection.swift in Sources */, 08F423382B45EC64005158F2 /* NetworkHTTPMethod.swift in Sources */, 08C4A3272B77CF3A00734378 /* SearchResultsArtistsSection.swift in Sources */, @@ -1501,6 +1517,14 @@ minimumVersion = 4.4.1; }; }; + 084AA25F2BC7E1F900CD152B /* XCRemoteSwiftPackageReference "Sparkle" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/sparkle-project/Sparkle"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.6.0; + }; + }; 0856A4F72B4B2F3D0073ACE7 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SDWebImage/SDWebImageSwiftUI.git"; @@ -1517,6 +1541,11 @@ package = 082683F42B8796D6007108E9 /* XCRemoteSwiftPackageReference "lottie-spm" */; productName = Lottie; }; + 084AA2602BC7E1F900CD152B /* Sparkle */ = { + isa = XCSwiftPackageProductDependency; + package = 084AA25F2BC7E1F900CD152B /* XCRemoteSwiftPackageReference "Sparkle" */; + productName = Sparkle; + }; 0856A4F82B4B2F3D0073ACE7 /* SDWebImageSwiftUI */ = { isa = XCSwiftPackageProductDependency; package = 0856A4F72B4B2F3D0073ACE7 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */; diff --git a/mupl/Common/Components/AppInfo/AppInfoView.swift b/mupl/Common/Components/AppInfo/AppInfoView.swift index 853a46a..a4f8c6f 100644 --- a/mupl/Common/Components/AppInfo/AppInfoView.swift +++ b/mupl/Common/Components/AppInfo/AppInfoView.swift @@ -6,41 +6,74 @@ // import SwiftUI +import Sparkle struct AppInfoView: View { + private let appUpdater: AppUpdater = .shared + var body: some View { - VStack(spacing: 16.0) { - VStack(spacing: 8.0) { + VStack(spacing: 0.0) { + HStack(alignment: .top, spacing: 24.0) { Image("Common/Logo") .resizable() .scaledToFit() - .frame(width: 80.0, height: 80.0) - .clipShape(.rect(cornerRadius: 16.0)) + .frame(width: 100.0, height: 100.0) + .clipShape(.rect(cornerRadius: 24.0)) - Text(Bundle.main.appName) - .font(.system(size: 24.0, weight: .bold)) - .foregroundStyle(Color.primaryText) + VStack(alignment: .leading, spacing: 0.0) { + VStack(alignment: .leading, spacing: 8.0) { + Text(Bundle.main.appName) + .font(.system(size: 24.0, weight: .bold)) + .foregroundStyle(Color.primaryText) + + Text("Apple Music player for macOS.") + .font(.system(size: 16.0)) + .foregroundStyle(Color.secondaryText) + } + + Spacer() + + Text("Version: \(Bundle.main.versionNumber)") + .font(.system(size: 14.0)) + } } + .frame(height: 100.0) + .frame(maxWidth: .infinity, alignment: .leading) - VStack(spacing: 4.0) { - Text("Version: \(Bundle.main.versionNumber)") - .font(.system(size: 14.0, weight: .medium)) - - Text("Licensed under MIT license.") - .font(.system(size: 12.0)) - } - .foregroundStyle(Color.secondaryText) + Spacer() - Image("Common/GitHub") - .resizable() - .scaledToFit() - .frame(width: 32.0, height: 32.0) - .tappable { - if let url = URL(string: "https://github.com/mupl-app/mupl-macos") { - NSWorkspace.shared.open(url) + VStack(spacing: 2.0) { + HStack(spacing: 2.0) { + Text("GitHub") + .foregroundStyle(Color.pinkAccent) + .tappable(hoverStyle: .init(padding: .init(vertical: 2.0, horizontal: 4.0))) { + if let url = URL(string: "https://github.com/mupl-app/mupl-macos") { + NSWorkspace.shared.open(url) + } + } + + Text("•") + .foregroundStyle(Color.secondaryText) + + if self.appUpdater.canCheckForUpdates { + Text("Latest") + .foregroundStyle(Color.secondaryText) + } else { + Text("Check for Updates") + .foregroundStyle(Color.pinkAccent) + .tappable(hoverStyle: .init(padding: .init(vertical: 2.0, horizontal: 4.0))) { + self.appUpdater.checkForUpdates() + } } } + .font(.system(size: 12.0)) + + Text("Licensed under MIT. Crafted with <3") + .font(.system(size: 10.0)) + .foregroundStyle(Color.secondaryText) + } } - .frame(width: 400.0, height: 400.0) + .padding(.all, 24.0) + .frame(width: 512.0, height: 216.0) } } diff --git a/mupl/Common/Extensions/UI/View + Tappable.swift b/mupl/Common/Extensions/UI/View + Tappable.swift index 2989ba0..e809c9e 100644 --- a/mupl/Common/Extensions/UI/View + Tappable.swift +++ b/mupl/Common/Extensions/UI/View + Tappable.swift @@ -13,7 +13,7 @@ struct TappableViewModifier: ViewModifier { let vertical: CGFloat let horizontal: CGFloat - init(vertical: CGFloat = .s2, horizontal: CGFloat = .s2) { + init(vertical: CGFloat = 8.0, horizontal: CGFloat = 8.0) { self.vertical = vertical self.horizontal = horizontal } @@ -33,7 +33,7 @@ struct TappableViewModifier: ViewModifier { let cornerRadius: CGFloat let colorSet: ColorSet - init(padding: Padding = .init(), cornerRadius: CGFloat = .s2, colorSet: ColorSet = .init()) { + init(padding: Padding = .init(), cornerRadius: CGFloat = 8.0, colorSet: ColorSet = .init()) { self.padding = padding self.cornerRadius = cornerRadius self.colorSet = colorSet diff --git a/mupl/Common/Models/Services/AppUpdater/AppUpdater.swift b/mupl/Common/Models/Services/AppUpdater/AppUpdater.swift new file mode 100644 index 0000000..e5c15f4 --- /dev/null +++ b/mupl/Common/Models/Services/AppUpdater/AppUpdater.swift @@ -0,0 +1,37 @@ +// +// AppUpdater.swift +// mupl +// +// Created by Tamerlan Satualdypov on 18.04.2024. +// + +import Foundation +import Sparkle +import Combine + +final class AppUpdater: ObservableObject { + static let shared: AppUpdater = .init() + + @Published var canCheckForUpdates: Bool = false + + private let updater: SPUUpdater + + private var cancellables: Set = .init() + + private init() { + self.updater = SPUStandardUpdaterController( + startingUpdater: true, + updaterDelegate: nil, + userDriverDelegate: nil + ).updater + + self.updater + .publisher(for: \.canCheckForUpdates) + .assign(to: &self.$canCheckForUpdates) + } + + func checkForUpdates() { + guard self.canCheckForUpdates else { return } + self.updater.checkForUpdates() + } +} diff --git a/mupl/Supporting Files/App/AppDelegate.swift b/mupl/Supporting Files/App/AppDelegate.swift index 649b2a6..8ec5b03 100644 --- a/mupl/Supporting Files/App/AppDelegate.swift +++ b/mupl/Supporting Files/App/AppDelegate.swift @@ -15,9 +15,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate { if self.appInfoWindow == nil { let window = NSWindow() - window.styleMask = [.closable, .miniaturizable, .titled] - window.title = "About \(Bundle.main.appName)" + window.styleMask = [.closable, .titled] window.contentView = NSHostingView(rootView: AppInfoView()) + window.titlebarAppearsTransparent = true + window.toolbarStyle = .unified window.center() self.appInfoWindow = NSWindowController(window: window) diff --git a/mupl/Supporting Files/Resources/Info.plist b/mupl/Supporting Files/Resources/Info.plist index f3d6f26..e9b35bf 100644 --- a/mupl/Supporting Files/Resources/Info.plist +++ b/mupl/Supporting Files/Resources/Info.plist @@ -14,5 +14,13 @@ 6.0 CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + LSApplicationCategoryType + public.app-category.music + SUEnableInstallerLauncherService + + SUFeedURL + https://github.com/mupl-app/mupl-macos/releases/latest/download/appcast.xml + SUPublicEDKey + u0r3lg6U36Yz0Kz2i8s9UNc9P8Ymx19Z6erMXW4NfT0= diff --git a/mupl/Supporting Files/Resources/mupl.entitlements b/mupl/Supporting Files/Resources/mupl.entitlements index 07792c4..dd369fd 100644 --- a/mupl/Supporting Files/Resources/mupl.entitlements +++ b/mupl/Supporting Files/Resources/mupl.entitlements @@ -12,5 +12,10 @@ com.apple.security.cs.disable-library-validation + com.apple.security.temporary-exception.mach-lookup.global-name + + $(PRODUCT_BUNDLE_IDENTIFIER)-spks + $(PRODUCT_BUNDLE_IDENTIFIER)-spki +