mirror of
https://github.com/wibus-wee/InjectGUI.git
synced 2025-11-25 11:29:26 +08:00
feat: setup sparkle framework
This commit is contained in:
51
.github/workflows/build.yml
vendored
51
.github/workflows/build.yml
vendored
@@ -34,13 +34,18 @@ jobs:
|
||||
# brew install graphicsmagick imagemagick
|
||||
|
||||
- name: Set up env.APP_CONF to Debug
|
||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
if: github.event_name != 'release'
|
||||
run: |
|
||||
echo "APP_CONF=Debug" >> $GITHUB_ENV
|
||||
- name: Set up env.APP_CONF to Release
|
||||
if: github.event_name == 'release'
|
||||
run: |
|
||||
echo "APP_CONF=Release" >> $GITHUB_ENV
|
||||
APP_VERSION=$(xcrun agvtool mvers -terse1)
|
||||
APP_BUILD=$(xcrun agvtool vers -terse)
|
||||
echo "APP_VERSION=$APP_VERSION" >> $GITHUB_ENV
|
||||
echo "APP_BUILD=$APP_BUILD" >> $GITHUB_ENV
|
||||
|
||||
- name: Build for macOS (Universal)
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -50,18 +55,52 @@ jobs:
|
||||
run: |
|
||||
hdiutil create -volname "InjectGUI" -srcfolder "build/Build/Products/${{ env.APP_CONF }}/InjectGUI.app" -ov -format UDZO "InjectGUI.dmg"
|
||||
|
||||
# - name: Create DMG
|
||||
# run: |
|
||||
# npm install --global create-dmg
|
||||
# create-dmg 'build/Build/Products/Release/InjectGUI.app' --overwrite --dmg-title='InjectGUI'
|
||||
|
||||
- name: Upload DMG Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: InjectGUI
|
||||
path: InjectGUI.dmg
|
||||
|
||||
- name: Upload DMG to GitHub Release
|
||||
if: github.event_name == 'release'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: InjectGUI.dmg
|
||||
|
||||
############################
|
||||
# Sparkle Appcast
|
||||
############################
|
||||
- name: Update Sparkle appcast
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
# SPARKLE_KEY: Sparkle EdDSA key exported from `generate_keys -x` as plain text
|
||||
# SPARKLE_CHANNEL: Seperate dev builds from default channel, to be specified in [SPUUpdaterDelegate allowedChannelsForUpdater:]
|
||||
# SPARKLE_DL_PREFIX: Prefix for the URL from where updates will be downloaded
|
||||
# SPARKLE_LINK: CodeEdit Website
|
||||
# https://github.com/wibus-wee/InjectGUI/releases/download/0.0.1-alpha.11/CodeEdit-9113dc5.dmg
|
||||
# RELEASE_NOTES_PREFIX: The URL to prefix before an update link:
|
||||
# https://codeedit.app/whats-new/raw/{v0.1.0} -- data in {} is inserted by sparkle
|
||||
# RELEASE_NOTES_URL: The URL of the entire release notes page: https://codeedit.app/whats-new
|
||||
SPARKLE_KEY: ${{ secrets.SPARKLE_KEY }}
|
||||
# SPARKLE_CHANNEL: dev
|
||||
SPARKLE_DL_PREFIX: "https://github.com/wibus-wee/InjectGUI/releases/download"
|
||||
SPARKLE_LINK: "https://github.com/wibus-wee/InjectGUI"
|
||||
APP_VERSION: ${{ env.APP_VERSION }}
|
||||
APP_BUILD: ${{ env.APP_BUILD }}
|
||||
# RELEASE_NOTES_URL: "https://codeedit.app/whats-new/"
|
||||
# RELEASE_NOTES_PREFIX: "https://codeedit.app/sparkle/"
|
||||
run: |
|
||||
SPARKLE_BIN="$RUNNER_TEMP/DerivedData/SourcePackages/artifacts/sparkle/Sparkle/bin"
|
||||
SPARKLE_ARCHIVE="$RUNNER_TEMP/Sparkle_Archive"
|
||||
echo -n "$SPARKLE_KEY" | tee "$RUNNER_TEMP/sparkle_key"
|
||||
mkdir "$SPARKLE_ARCHIVE"
|
||||
cp "$RUNNER_TEMP/InjectGUI.dmg" "$SPARKLE_ARCHIVE"
|
||||
SPARKLE_SIG=$("$SPARKLE_BIN/sign_update" --ed-key-file "$RUNNER_TEMP/sparkle_key" "$SPARKLE_ARCHIVE/InjectGUI.dmg" | cut -d\" -f2)
|
||||
echo "<!DOCTYPE>" > "$SPARKLE_ARCHIVE/InjectGUI.html" # Need a blank html doc with the DOCTYPE tag to trick sparkle into loading our remote release notes.
|
||||
"$SPARKLE_BIN/generate_appcast" --ed-key-file "$RUNNER_TEMP/sparkle_key" --download-url-prefix "${{ env.SPARKLE_DL_PREFIX }}/v${{ env.APP_VERSION }}/" --link "$SPARKLE_LINK" --maximum-deltas 0 "$SPARKLE_ARCHIVE"
|
||||
|
||||
- name: Upload Sparkle Appcast
|
||||
if: github.event_name == 'release'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: "${{ RUNNER.TEMP }}/Sparkle_Archive/appcast.xml"
|
||||
@@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
380D777B2C61EA56005F3150 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 380D777A2C61EA56005F3150 /* Sparkle */; };
|
||||
380D777D2C61EAB9005F3150 /* CheckForUpdatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 380D777C2C61EAB9005F3150 /* CheckForUpdatesView.swift */; };
|
||||
381027E02C5F784F00348460 /* Extension+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381027DF2C5F784F00348460 /* Extension+Scene.swift */; };
|
||||
381027E22C5F7C4800348460 /* Extension+Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381027E12C5F7C4800348460 /* Extension+Font.swift */; };
|
||||
381027E42C5F7E1100348460 /* Extension+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381027E32C5F7E1100348460 /* Extension+URL.swift */; };
|
||||
@@ -36,6 +38,8 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
380D777C2C61EAB9005F3150 /* CheckForUpdatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckForUpdatesView.swift; sourceTree = "<group>"; };
|
||||
380D777E2C61ED32005F3150 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
381027DF2C5F784F00348460 /* Extension+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extension+Scene.swift"; sourceTree = "<group>"; };
|
||||
381027E12C5F7C4800348460 /* Extension+Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extension+Font.swift"; sourceTree = "<group>"; };
|
||||
381027E32C5F7E1100348460 /* Extension+URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extension+URL.swift"; sourceTree = "<group>"; };
|
||||
@@ -72,6 +76,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
38E944F52C5A7F6A00B252A3 /* Cache in Frameworks */,
|
||||
380D777B2C61EA56005F3150 /* Sparkle in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -98,6 +103,7 @@
|
||||
38877A1B2C4A6F83009F5910 /* InjectGUI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
380D777E2C61ED32005F3150 /* Info.plist */,
|
||||
38877A3B2C4A9EAB009F5910 /* Util */,
|
||||
38877A382C4A7306009F5910 /* App */,
|
||||
38877A312C4A7217009F5910 /* Extension */,
|
||||
@@ -141,6 +147,7 @@
|
||||
38AD95ED2C58F59C0032E79F /* StatusView.swift */,
|
||||
38BC1F5B2C4BB02200C3B60E /* SettingsView.swift */,
|
||||
387CEA782C5BD9C400E3A5AC /* AdminPrivilegeView.swift */,
|
||||
380D777C2C61EAB9005F3150 /* CheckForUpdatesView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@@ -193,6 +200,7 @@
|
||||
name = InjectGUI;
|
||||
packageProductDependencies = (
|
||||
38E944F42C5A7F6A00B252A3 /* Cache */,
|
||||
380D777A2C61EA56005F3150 /* Sparkle */,
|
||||
);
|
||||
productName = InjectGUI;
|
||||
productReference = 38877A192C4A6F83009F5910 /* InjectGUI.app */;
|
||||
@@ -225,6 +233,7 @@
|
||||
mainGroup = 38877A102C4A6F83009F5910;
|
||||
packageReferences = (
|
||||
38E944F32C5A7F6A00B252A3 /* XCRemoteSwiftPackageReference "Cache" */,
|
||||
380D77792C61EA56005F3150 /* XCRemoteSwiftPackageReference "Sparkle" */,
|
||||
);
|
||||
productRefGroup = 38877A1A2C4A6F83009F5910 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -275,6 +284,7 @@
|
||||
381027E22C5F7C4800348460 /* Extension+Font.swift in Sources */,
|
||||
387CEA792C5BD9C400E3A5AC /* AdminPrivilegeView.swift in Sources */,
|
||||
38AD95EE2C58F59C0032E79F /* StatusView.swift in Sources */,
|
||||
380D777D2C61EAB9005F3150 /* CheckForUpdatesView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -416,6 +426,7 @@
|
||||
DEVELOPMENT_ASSET_PATHS = "\"InjectGUI/Preview Content\"";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = InjectGUI/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||
@@ -454,6 +465,7 @@
|
||||
DEVELOPMENT_ASSET_PATHS = "\"InjectGUI/Preview Content\"";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = InjectGUI/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||
@@ -505,6 +517,14 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
380D77792C61EA56005F3150 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/sparkle-project/Sparkle";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 2.0.0;
|
||||
};
|
||||
};
|
||||
38E944F32C5A7F6A00B252A3 /* XCRemoteSwiftPackageReference "Cache" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/hyperoslo/Cache";
|
||||
@@ -516,6 +536,11 @@
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
380D777A2C61EA56005F3150 /* Sparkle */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 380D77792C61EA56005F3150 /* XCRemoteSwiftPackageReference "Sparkle" */;
|
||||
productName = Sparkle;
|
||||
};
|
||||
38E944F42C5A7F6A00B252A3 /* Cache */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 38E944F32C5A7F6A00B252A3 /* XCRemoteSwiftPackageReference "Cache" */;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Sparkle
|
||||
|
||||
let configuration = Configuration.shared
|
||||
let injectConfiguration = InjectConfiguration.shared
|
||||
@@ -16,8 +17,12 @@ let executor = Executor.shared
|
||||
@main
|
||||
struct InjectGUIApp: App {
|
||||
@AppStorage("showAdminPrivilegeView") private var showAdminPrivilegeView: Bool = true
|
||||
private let updaterController: SPUStandardUpdaterController
|
||||
|
||||
init() {
|
||||
// If you want to start the updater manually, pass false to startingUpdater and call .startUpdater() later
|
||||
// This is where you can also pass an updater delegate if you need one
|
||||
updaterController = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil)
|
||||
setupApplicationSupportDirectory()
|
||||
checkPassword()
|
||||
}
|
||||
@@ -29,7 +34,12 @@ struct InjectGUIApp: App {
|
||||
AdminPrivilegeView()
|
||||
}
|
||||
}
|
||||
.commands { SidebarCommands() }
|
||||
.commands {
|
||||
SidebarCommands()
|
||||
CommandGroup(after: .appInfo) {
|
||||
CheckForUpdatesView(updater: updaterController.updater)
|
||||
}
|
||||
}
|
||||
.contentSizedWindowResizability()
|
||||
|
||||
Settings {
|
||||
|
||||
10
InjectGUI/Info.plist
Normal file
10
InjectGUI/Info.plist
Normal file
@@ -0,0 +1,10 @@
|
||||
<?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>SUFeedURL</key>
|
||||
<string>https://github.com/wibus-wee/InjectGUI/releases/download/latest/appcast.xml</string>
|
||||
<key>SUPublicEDKey</key>
|
||||
<string>uj8dRzY60RpQhFt88Lm4vwy7a5TEceTqRWmBeZpb4e0=</string>
|
||||
</dict>
|
||||
</plist>
|
||||
39
InjectGUI/View/CheckForUpdatesView.swift
Normal file
39
InjectGUI/View/CheckForUpdatesView.swift
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// CheckForUpdatesView.swift
|
||||
// InjectGUI
|
||||
//
|
||||
// Created by wibus on 2024/8/6.
|
||||
//
|
||||
|
||||
|
||||
import SwiftUI
|
||||
import Sparkle
|
||||
|
||||
// This view model class publishes when new updates can be checked by the user
|
||||
final class CheckForUpdatesViewModel: ObservableObject {
|
||||
@Published var canCheckForUpdates = false
|
||||
|
||||
init(updater: SPUUpdater) {
|
||||
updater.publisher(for: \.canCheckForUpdates)
|
||||
.assign(to: &$canCheckForUpdates)
|
||||
}
|
||||
}
|
||||
|
||||
// This is the view for the Check for Updates menu item
|
||||
// Note this intermediate view is necessary for the disabled state on the menu item to work properly before Monterey.
|
||||
// See https://stackoverflow.com/questions/68553092/menu-not-updating-swiftui-bug for more info
|
||||
struct CheckForUpdatesView: View {
|
||||
@ObservedObject private var checkForUpdatesViewModel: CheckForUpdatesViewModel
|
||||
private let updater: SPUUpdater
|
||||
|
||||
init(updater: SPUUpdater) {
|
||||
self.updater = updater
|
||||
// Create our view model for our CheckForUpdatesView
|
||||
self.checkForUpdatesViewModel = CheckForUpdatesViewModel(updater: updater)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button("Check for Updates…", action: updater.checkForUpdates)
|
||||
.disabled(!checkForUpdatesViewModel.canCheckForUpdates)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user