From c0a81edf6b5023abecf7373574b0f0c62d1ae06e Mon Sep 17 00:00:00 2001
From: neoarz <164915254+neoarz@users.noreply.github.com>
Date: Mon, 20 Jan 2025 23:32:24 -0500
Subject: [PATCH 01/14] Update trustedapps.json
Signed-off-by: neoarz <164915254+neoarz@users.noreply.github.com>
---
trustedapps.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/trustedapps.json b/trustedapps.json
index fd3a5af9..69c08e8b 100644
--- a/trustedapps.json
+++ b/trustedapps.json
@@ -12,6 +12,10 @@
"identifier": "org.provenance-emu.provenance",
"sourceURL": "https://provenance-emu.com/apps.json"
},
+ {
+ "identifier": "com.neo.countdown",
+ "sourceURL": "https://neoarz.github.io/Countdown-App/Countdown.json"
+ },
{
"identifier": "me.oatmealdome.altstore",
"sourceURL": "https://altstore.oatmealdome.me"
@@ -61,6 +65,10 @@
"identifier": "org.provenance-emu.provenance",
"sourceURL": "https://provenance-emu.com/apps.json"
},
+ {
+ "identifier": "com.neo.countdown",
+ "sourceURL": "https://neoarz.github.io/Countdown-App/Countdown.json"
+ },
{
"identifier": "me.oatmealdome.altstore",
"sourceURL": "https://altstore.oatmealdome.me"
From 1641f6e93f317aee510b0df319f58bb944ee9a18 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Tue, 21 Jan 2025 21:53:29 +0530
Subject: [PATCH 02/14] [ToastView]: Fix: restore back to printing
localizedDescription as before
---
AltStore/Components/ToastView.swift | 16 +++++++++++++---
AltStore/LaunchViewController.swift | 2 +-
.../dignostics/errors/ErrorProcessing.swift | 19 +++++++++++--------
3 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/AltStore/Components/ToastView.swift b/AltStore/Components/ToastView.swift
index f940b4ac..b563d811 100644
--- a/AltStore/Components/ToastView.swift
+++ b/AltStore/Components/ToastView.swift
@@ -65,13 +65,23 @@ class ToastView: RSTToastView
self.opensErrorLog = opensLog
}
- convenience init(error: Error)
+ enum InfoMode: String {
+ case fullError
+ case localizedDescription
+ }
+
+ convenience init(error: Error){
+ self.init(error: error, mode: .localizedDescription)
+ }
+
+ convenience init(error: Error, mode: InfoMode)
{
let error = error as NSError
+ let mode = mode == .fullError ? ErrorProcessing.InfoMode.fullError : ErrorProcessing.InfoMode.localizedDescription
let text = error.localizedTitle ?? NSLocalizedString("Operation Failed", comment: "")
- let detailText = ErrorProcessing(.fullError).getDescription(error: error)
-
+ let detailText = ErrorProcessing(mode).getDescription(error: error)
+
self.init(text: text, detailText: detailText)
}
diff --git a/AltStore/LaunchViewController.swift b/AltStore/LaunchViewController.swift
index 13c42c80..d06242c6 100644
--- a/AltStore/LaunchViewController.swift
+++ b/AltStore/LaunchViewController.swift
@@ -316,7 +316,7 @@ extension LaunchViewController
let errorDesc = ErrorProcessing(.fullError).getDescription(error: error as NSError)
print("Failed to update sources on launch. \(errorDesc)")
- let toastView = ToastView(error: error)
+ let toastView = ToastView(error: error, mode: .fullError)
toastView.addTarget(self.destinationViewController, action: #selector(TabBarController.presentSources), for: .touchUpInside)
toastView.show(in: self.destinationViewController.selectedViewController ?? self.destinationViewController)
}
diff --git a/SideStore/Utils/dignostics/errors/ErrorProcessing.swift b/SideStore/Utils/dignostics/errors/ErrorProcessing.swift
index 15489f58..3e46c659 100644
--- a/SideStore/Utils/dignostics/errors/ErrorProcessing.swift
+++ b/SideStore/Utils/dignostics/errors/ErrorProcessing.swift
@@ -27,7 +27,7 @@ class ErrorProcessing {
self.recur = recur
}
- private func processError(_ error: NSError, getMoreErrors: (_ error: NSError)->String) -> String{
+ private func processError(_ error: NSError, ignoreTitle: Bool = false, getMoreErrors: (_ error: NSError)->String) -> String{
// if unique was requested and if this error is duplicate, ignore processing it
let serializedError = "\(error)"
if unique && errors.contains(serializedError) {
@@ -39,7 +39,7 @@ class ErrorProcessing {
var desc = ""
switch (info){
case .localizedDescription:
- title = (error.localizedTitle.map{$0+"\n"} ?? "")
+ title = !ignoreTitle ? (error.localizedTitle.map{$0+"\n"} ?? "") : ""
desc = error.localizedDescription
case .fullError:
desc = serializedError
@@ -54,13 +54,14 @@ class ErrorProcessing {
return getDescriptionText(error: error)
}
- private lazy var recurseErrors = { error in
- self.getDescriptionText(error: error) // recursively process underlying error(s) if any
- }
- func getDescriptionText(error: NSError) -> String{
+ func getDescriptionText(error: NSError,_ depth: Int = 0) -> String{
+ // closure
+ let recurseErrors = { error in
+ self.getDescriptionText(error: error, depth+1) // recursively process underlying error(s) if any
+ }
+
var description = ""
-
// process current error only if recur was not requested
let processMoreErrors = recur ? recurseErrors : {_ in ""}
@@ -74,7 +75,9 @@ class ErrorProcessing {
let error = underlyingError as NSError
description += processError(error, getMoreErrors: processMoreErrors)
} else {
- description += processError(error, getMoreErrors: processMoreErrors)
+ // ignore the title for the base error since we wanted this to be description
+ let isBaseError = (depth == 0)
+ description += processError(error, ignoreTitle: isBaseError, getMoreErrors: processMoreErrors)
}
return description
}
From 13d924abf64d3c7d96061a2bff816d9789681530 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Tue, 21 Jan 2025 23:47:46 +0530
Subject: [PATCH 03/14] [CONTRIBUTING]: updated build steps
---
CONTRIBUTING.md | 44 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 78443779..8f4b9c6e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -50,17 +50,55 @@ to force it to check for new binaries, run `bash ./SideStore/fetch-prebuilt.sh f
## Building an IPA for distribution
Install cocoapods if required using: `brew install cocoapods`
-
Now perform Pod-Install using: `pod install` command to install the dependencies.
-You can then use the Makefile command: `make build fakesign ipa` in the root directory.
-
+You can then use the Makefile command: `make build fakesign ipa` in the root directory.
+By default the config for build is: `Release`
+For debug builds: `export BUILD_CONFIG=Debug;make build fakesign ipa` in the root directory.
+For alpha/beta builds: `export IS_ALPHA=1;` or `export IS_BETA=1;` before invoking the build command.
This will create SideStore.ipa.
+```sh
+Examples:
+
+ # cocoapods
+ brew install cocoapods
+ # perform installation of the pods
+ pod install
+
+ # alpha release build
+ export IS_ALPHA=1;make build fakesign ipa
+ # alpha debug build
+ export IS_ALPHA=1;export BUILD_CONFIG=Debug;make build fakesign ipa
+
+ # beta release build
+ export IS_BETA=1;make build fakesign ipa
+ # beta debug build
+ export IS_BETA=1;export BUILD_CONFIG=Debug;make build fakesign ipa
+
+ # stable release build
+ make build fakesign ipa
+ # stable debug build
+ export BUILD_CONFIG=Debug;make build fakesign ipa
+```
+By default sidestore will build for its default bundleIdentifier `com.SideStore.SideStore` but if you need to set a custom bundleID for commandline builds, once can do so by exporting `BUNDLE_ID_SUFFIX` env var
+```sh
+ # stable release build
+ export BUNDLE_ID_SUFFIX=XYZ0123456;make build fakesign ipa
+ # stable debug build
+ export BUNDLE_ID_SUFFIX=XYZ0123456;export BUILD_CONFIG=Debug;make build fakesign ipa
+```
+NOTE: When building from XCode, the `BUNDLE_ID_SUFFIX` is set by default with the value of `DEVELOPMENT_TEAM`
+
+This can be customized by setting/removing the BUNDLE_ID_SUFFIX in overriding CodeSigning.xcconfig created from CodeSigning.xcconfig.sample
+
+
+
> **Warning**
>
> The binary created will contain paths to Xcode's DerivedData, and if you built minimuxer on your machine, paths to $HOME/.cargo. This will include your username. If you want to keep your user's
> username private, you might want to get GitHub Actions to build the IPA instead.
+>
## Developing minimuxer alongside SideStore
From c6f843ebc330462135af1728c71867a835dc39e1 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Wed, 22 Jan 2025 01:47:21 +0530
Subject: [PATCH 04/14] [BuildInfo]: Added bundleInfo inspection to create
version tag in Settings screen
---
AltBackup/Info.plist | 2 +
AltStore.xcodeproj/project.pbxproj | 14 +++++
AltStore/Info.plist | 2 +
.../Settings/SettingsViewController.swift | 47 ++++++---------
AltStoreCore/Info.plist | 2 +
AltWidget/Info.plist | 2 +
Build.xcconfig | 1 +
CodeSigning.xcconfig.sample | 4 ++
SideStore/Utils/buildinfo/BuildInfo.swift | 58 +++++++++++++++++++
9 files changed, 104 insertions(+), 28 deletions(-)
create mode 100644 SideStore/Utils/buildinfo/BuildInfo.swift
diff --git a/AltBackup/Info.plist b/AltBackup/Info.plist
index 87318f17..f3345af1 100644
--- a/AltBackup/Info.plist
+++ b/AltBackup/Info.plist
@@ -37,6 +37,8 @@
BuildRevision
$(BUILD_REVISION)
+ BuildChannel
+ $(BUILD_CHANNEL)
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
LSRequiresIPhoneOS
diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj
index 914ff9a8..b2cab4ba 100644
--- a/AltStore.xcodeproj/project.pbxproj
+++ b/AltStore.xcodeproj/project.pbxproj
@@ -65,6 +65,8 @@
A86315DF2D3EB2DE0048FA40 /* ErrorProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */; };
A868CFE42D31999A002F1201 /* SingletonGenericMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868CFE32D319988002F1201 /* SingletonGenericMap.swift */; };
A8696EE42D34512C00E96389 /* RemoveAppExtensionsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */; };
+ A888EAD52D401D8F0026F7E3 /* BuildInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A888EAD42D401D8A0026F7E3 /* BuildInfo.swift */; };
+ A888EAD62D4020770026F7E3 /* BuildInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A888EAD42D401D8A0026F7E3 /* BuildInfo.swift */; };
A88B8C492D35AD3200F53F9D /* OperationsLoggingContolView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */; };
A88B8C552D35F1EC00F53F9D /* OperationsLoggingControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88B8C542D35F1EC00F53F9D /* OperationsLoggingControl.swift */; };
A8945AA62D059B6100D86CBE /* Roxas.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8945AA52D059B6100D86CBE /* Roxas.framework */; };
@@ -649,6 +651,7 @@
A86315DE2D3EB2D80048FA40 /* ErrorProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorProcessing.swift; sourceTree = ""; };
A868CFE32D319988002F1201 /* SingletonGenericMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingletonGenericMap.swift; sourceTree = ""; };
A8696EE32D34512C00E96389 /* RemoveAppExtensionsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAppExtensionsOperation.swift; sourceTree = ""; };
+ A888EAD42D401D8A0026F7E3 /* BuildInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildInfo.swift; sourceTree = ""; };
A88B8C482D35AD3200F53F9D /* OperationsLoggingContolView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationsLoggingContolView.swift; sourceTree = ""; };
A88B8C542D35F1EC00F53F9D /* OperationsLoggingControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationsLoggingControl.swift; sourceTree = ""; };
A8945AA52D059B6100D86CBE /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1224,6 +1227,14 @@
path = errors;
sourceTree = "";
};
+ A888EAD32D401D7C0026F7E3 /* buildinfo */ = {
+ isa = PBXGroup;
+ children = (
+ A888EAD42D401D8A0026F7E3 /* BuildInfo.swift */,
+ );
+ path = buildinfo;
+ sourceTree = "";
+ };
A88B8C532D35F1E800F53F9D /* operations */ = {
isa = PBXGroup;
children = (
@@ -1288,6 +1299,7 @@
A8C38C1C2D2068D100E83DBD /* Utils */ = {
isa = PBXGroup;
children = (
+ A888EAD32D401D7C0026F7E3 /* buildinfo */,
A8AD35572D31BEB2003A28B4 /* datastructures */,
A8A853AD2D3050CC00995795 /* pagination */,
A8087E712D2D291B002DB21B /* importexport */,
@@ -2910,6 +2922,7 @@
0E05025C2BEC947000879B5C /* String+SideStore.swift in Sources */,
0EE7FDCB2BE8D12B00D1E390 /* ALTLocalizedError.swift in Sources */,
BF66EEA92501AEC5007EE018 /* Tier.swift in Sources */,
+ A888EAD62D4020770026F7E3 /* BuildInfo.swift in Sources */,
BF66EEDB2501AECA007EE018 /* StoreApp.swift in Sources */,
D5CE309C2B4C946300DB8151 /* AltStore15ToAltStore16.xcmappingmodel in Sources */,
BF66EEDE2501AECA007EE018 /* AppID.swift in Sources */,
@@ -3054,6 +3067,7 @@
BFF00D302501BD7D00746320 /* Intents.intentdefinition in Sources */,
D5B6F6AB2AD76541007EED5A /* PreviewAppScreenshotsViewController.swift in Sources */,
BFD2476E2284B9A500981D42 /* AppDelegate.swift in Sources */,
+ A888EAD52D401D8F0026F7E3 /* BuildInfo.swift in Sources */,
BF41B806233423AE00C593A3 /* TabBarController.swift in Sources */,
BFE00A202503097F00EB4D0C /* INInteraction+AltStore.swift in Sources */,
BFDB6A0B22AAEDB7007EA6D6 /* Operation.swift in Sources */,
diff --git a/AltStore/Info.plist b/AltStore/Info.plist
index cfe47fc9..031b11d9 100644
--- a/AltStore/Info.plist
+++ b/AltStore/Info.plist
@@ -83,6 +83,8 @@
$(CURRENT_PROJECT_VERSION)
BuildRevision
$(BUILD_REVISION)
+ BuildChannel
+ $(BUILD_CHANNEL)
INIntentsSupported
RefreshAllIntent
diff --git a/AltStore/Settings/SettingsViewController.swift b/AltStore/Settings/SettingsViewController.swift
index 88e09eb4..26d066c4 100644
--- a/AltStore/Settings/SettingsViewController.swift
+++ b/AltStore/Settings/SettingsViewController.swift
@@ -211,20 +211,11 @@ private extension SettingsViewController
{
private func getVersionLabel() -> String {
- let MARKETING_VERSION_KEY = "CFBundleShortVersionString"
- let BUILD_REVISION = "CFBundleRevision" // commit ID for now (but could be any, set by build env vars
- let CURRENT_PROJECT_VERSION = kCFBundleVersionKey as String
+ let buildInfo = BuildInfo()
func getXcodeVersion() -> String {
- let XCODE_VERSION = "DTXcode"
- let XCODE_REVISION = "DTXcodeBuild"
-
- let xcode = Bundle.main.object(forInfoDictionaryKey: XCODE_VERSION) as? String
- let build = Bundle.main.object(forInfoDictionaryKey: XCODE_REVISION) as? String
-
- var xcodeVersion = xcode.map { version in
-// " - Xcode \(version) - " + (build.map { revision in "\(revision)" } ?? "") // Ex: "0.6.0 - Xcode 16.2 - 21ac1ef"
- "Xcode \(version) - " + (build.map { revision in "\(revision)" } ?? "") // Ex: "0.6.0 - Xcode 16.2 - 21ac1ef"
+ var xcodeVersion = buildInfo.xcode.map { version in
+ "Xcode \(version)" + (buildInfo.xcode_revision.map { revision in " - \(revision)" } ?? "") // Ex: "0.6.0 - Xcode 16.2 - 21ac1ef"
} ?? ""
if let pairing = Bundle.main.object(forInfoDictionaryKey: "ALTPairingFile") as? String,
@@ -234,26 +225,25 @@ private extension SettingsViewController
return xcodeVersion
}
+
var versionLabel: String = ""
if let installedApp = InstalledApp.fetchAltStore(in: DatabaseManager.shared.viewContext)
{
- #if BETA
- // Only show build version (and build revision) for BETA builds.
- let bundleVersion: String? = Bundle.main.object(forInfoDictionaryKey: CURRENT_PROJECT_VERSION) as? String
- let buildRevision: String? = Bundle.main.object(forInfoDictionaryKey: BUILD_REVISION) as? String
+ let isStableBuild = (buildInfo.channel == .stable)
+ let revision = buildInfo.revision ?? ""
- var localizedVersion = bundleVersion.map { version in
- "\(installedApp.version) (\(version))" + (buildRevision.map { revision in " - \(revision)" } ?? "") // Ex: "0.6.0 (0600) - 1acdef3"
- } ?? installedApp.localizedVersion
-
- #else
var localizedVersion = installedApp.version
- #endif
-
+ // Only show build version (and build revision) for non stable builds.
+ if !isStableBuild {
+ localizedVersion += buildInfo.project_version.map{ version in
+ version.isEmpty ? "" : " (\(version))" + (revision.isEmpty ? "" : " - \(revision)")
+ } ?? installedApp.localizedVersion
+ }
+
versionLabel = NSLocalizedString(String(format: "Version %@", localizedVersion), comment: "SideStore Version")
}
- else if let version = Bundle.main.object(forInfoDictionaryKey: MARKETING_VERSION_KEY) as? String
+ else if let version = buildInfo.marketing_version
{
var version = "SideStore \(version)"
@@ -268,10 +258,11 @@ private extension SettingsViewController
versionLabel = NSLocalizedString(version, comment: "SideStore Version")
}
- // add xcode build version if in debug mode
- #if DEBUG
- versionLabel += "\n\(getXcodeVersion())"
- #endif
+ // add xcode build version for local builds
+ if buildInfo.channel == .local
+ {
+ versionLabel += "\n\(getXcodeVersion())"
+ }
return versionLabel
}
diff --git a/AltStoreCore/Info.plist b/AltStoreCore/Info.plist
index cebb1257..cc1fbfd2 100644
--- a/AltStoreCore/Info.plist
+++ b/AltStoreCore/Info.plist
@@ -18,6 +18,8 @@
$(MARKETING_VERSION)
BuildRevision
$(BUILD_REVISION)
+ BuildChannel
+ $(BUILD_CHANNEL)
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
diff --git a/AltWidget/Info.plist b/AltWidget/Info.plist
index cf410522..31fda5f7 100644
--- a/AltWidget/Info.plist
+++ b/AltWidget/Info.plist
@@ -24,6 +24,8 @@
$(MARKETING_VERSION)
BuildRevision
$(BUILD_REVISION)
+ BuildChannel
+ $(BUILD_CHANNEL)
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSExtension
diff --git a/Build.xcconfig b/Build.xcconfig
index 93135631..d46cb8d0 100644
--- a/Build.xcconfig
+++ b/Build.xcconfig
@@ -3,6 +3,7 @@
MARKETING_VERSION = 0.6.0
CURRENT_PROJECT_VERSION = 6000
+BUILD_CHANNEL = stable
// Vars to be overwritten by `CodeSigning.xcconfig` if exists
DEVELOPMENT_TEAM = S32Z3HMYVQ
diff --git a/CodeSigning.xcconfig.sample b/CodeSigning.xcconfig.sample
index e0a5f1b0..31a8c67a 100644
--- a/CodeSigning.xcconfig.sample
+++ b/CodeSigning.xcconfig.sample
@@ -15,6 +15,10 @@ ORG_IDENTIFIER = com.myuniquename
// we don't want to do this for release since those builds will most likely be installed via SideServer, which adds the team ID
BUNDLE_ID_SUFFIX = .$(DEVELOPMENT_TEAM)
+// Comment this out to use default 'stable' channel defined in Build.xcconfig
+// For local xcode or commandline builds we can use local channel for local build specific logic
+BUILD_CHANNEL = local
+
// Set to YES if you have a valid paid Apple Developer account
DEVELOPER_ACCOUNT_PAID = NO
diff --git a/SideStore/Utils/buildinfo/BuildInfo.swift b/SideStore/Utils/buildinfo/BuildInfo.swift
new file mode 100644
index 00000000..5e800ba1
--- /dev/null
+++ b/SideStore/Utils/buildinfo/BuildInfo.swift
@@ -0,0 +1,58 @@
+//
+// BuildInfo.swift
+// AltStore
+//
+// Created by Magesh K on 21/01/25.
+// Copyright © 2025 SideStore. All rights reserved.
+//
+
+public class BuildInfo{
+ private static let BUILD_REVISION_TAG = "BuildRevision" // commit ID for now (but could be any, set by build env vars
+ private static let BUILD_CHANNEL_TAG = "BuildChannel" // set by build env, ex CI will set it via env vars, for xcode builds this is empty
+
+ private static let MARKETING_VERSION_TAG = "CFBundleShortVersionString"
+ private static let CURRENT_PROJECT_VERSION_TAG = kCFBundleVersionKey as String
+
+ private static let XCODE_VERSION_TAG = "DTXcode"
+ private static let XCODE_REVISION_TAG = "DTXcodeBuild"
+
+ public enum Channel: String {
+ case unknown
+ case local // xcodebuilds can use this by setting BUILD_CHANNEL in CodeSigning.xcconfig
+
+ case alpha
+ case beta
+ case stable
+ }
+
+ public lazy var channel: Channel = {
+ let channel = Bundle.main.object(forInfoDictionaryKey: Self.BUILD_CHANNEL_TAG) as? String
+ return Channel(rawValue: channel ?? "") ?? .unknown
+ }()
+
+ public lazy var revision: String? = {
+ let revision = Bundle.main.object(forInfoDictionaryKey: Self.BUILD_REVISION_TAG) as? String
+ return revision
+ }()
+
+ public lazy var project_version: String? = {
+ let revision = Bundle.main.object(forInfoDictionaryKey: Self.CURRENT_PROJECT_VERSION_TAG) as? String
+ return revision
+ }()
+
+ public lazy var marketing_version: String? = {
+ let revision = Bundle.main.object(forInfoDictionaryKey: Self.MARKETING_VERSION_TAG) as? String
+ return revision
+ }()
+
+ public lazy var xcode: String? = {
+ let xcode = Bundle.main.object(forInfoDictionaryKey: Self.XCODE_VERSION_TAG) as? String
+ return xcode
+ }()
+
+ public lazy var xcode_revision: String? = {
+ let revision = Bundle.main.object(forInfoDictionaryKey: Self.XCODE_REVISION_TAG) as? String
+ return revision
+ }()
+
+}
From 203a7e6f11a266ece4a853cc9abfbbe4dd228d89 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Wed, 22 Jan 2025 02:02:50 +0530
Subject: [PATCH 05/14] [CI]: set to BUILD_CHANNEL based on CI build type
---
Makefile | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index b6e14108..c2a33d47 100755
--- a/Makefile
+++ b/Makefile
@@ -161,19 +161,24 @@ test:
IS_ALPHA_TRUE := $(filter true TRUE 1, $(IS_ALPHA))
IS_BETA_TRUE := $(filter true TRUE 1, $(IS_BETA))
+# set build types to embed into Info.plist for key: BuildChannel
+BUILD_CHANNEL := stable
+BUILD_CHANNEL := $(if $(IS_ALPHA_TRUE),alpha,$(BUILD_CHANNEL))
+BUILD_CHANNEL := $(if $(IS_BETA_TRUE),beta,$(BUILD_CHANNEL))
+
# Fetch the latest commit ID for ALPHA or BETA builds
COMMIT_ID := $(if $(or $(IS_ALPHA_TRUE),$(IS_BETA_TRUE)),$(shell git rev-parse --short HEAD),)
# Print release type based on the value of IS_ALPHA or IS_BETA
print_release_type:
@echo ""
- @if [ "$(filter true TRUE 1,$(IS_ALPHA))" ]; then \
+ @if [ $(IS_ALPHA_TRUE) ]; then \
echo "'IS_ALPHA' is set to true. Fetched the latest commit ID from HEAD..."; \
echo " Commit ID: $(COMMIT_ID)"; \
echo ""; \
echo ">>>>>>>> This is now an ALPHA release for COMMIT_ID = '$(COMMIT_ID)' <<<<<<<<<"; \
echo " Building with BUILD_REVISION = '$(COMMIT_ID)'"; \
- elif [ "$(filter true TRUE 1,$(IS_BETA))" ]; then \
+ elif [ $(IS_BETA_TRUE) ]; then \
echo "'IS_BETA' is set to true. Fetched the latest commit ID from HEAD..."; \
echo " Commit ID: $(COMMIT_ID)"; \
echo ""; \
@@ -215,6 +220,7 @@ build: print_release_type
DEVELOPMENT_TEAM=XYZ0123456 \
ORG_IDENTIFIER=com.SideStore \
BUILD_REVISION=$(COMMIT_ID) \
+ BUILD_CHANNEL=$(BUILD_CHANNEL)
BUNDLE_ID_SUFFIX=
# DWARF_DSYM_FOLDER_PATH="."
From 7ed8c20dfc94544fbf6cb46c87e035f177d09586 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Wed, 22 Jan 2025 04:38:46 +0530
Subject: [PATCH 06/14] [Backup]: Fix: update logic during install missed since
override keyword was missing
---
.../FetchProvisioningProfilesOperation.swift | 68 +++++++++----------
1 file changed, 34 insertions(+), 34 deletions(-)
diff --git a/AltStore/Operations/FetchProvisioningProfilesOperation.swift b/AltStore/Operations/FetchProvisioningProfilesOperation.swift
index 471aabbb..0690b2f3 100644
--- a/AltStore/Operations/FetchProvisioningProfilesOperation.swift
+++ b/AltStore/Operations/FetchProvisioningProfilesOperation.swift
@@ -119,6 +119,36 @@ class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProvisioni
return value
}
}
+
+ internal func fetchProvisioningProfile(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void)
+ {
+ ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
+ switch Result(profile, error)
+ {
+ case .failure(let error): completionHandler(.failure(error))
+ case .success(let profile):
+
+ // Delete existing profile
+ ALTAppleAPI.shared.delete(profile, for: team, session: session) { (success, error) in
+ switch Result(success, error)
+ {
+ case .failure:
+ // As of March 20, 2023, the free provisioning profile is re-generated each fetch, and you can no longer delete it.
+ // So instead, we just return the fetched profile from above.
+ completionHandler(.success(profile))
+
+ case .success:
+ Logger.sideload.notice("Generating new free provisioning profile for App ID \(appID.bundleIdentifier, privacy: .public).")
+
+ // Fetch new provisioning profile
+ ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
+ completionHandler(Result(profile, error))
+ }
+ }
+ }
+ }
+ }
+ }
}
extension FetchProvisioningProfilesOperation
@@ -223,7 +253,7 @@ extension FetchProvisioningProfilesOperation
//process
self.fetchProvisioningProfile(
- for: appID, team: team, session: session, completionHandler: completionHandler
+ for: appID, app: app, team: team, session: session, completionHandler: completionHandler
)
}
}
@@ -328,36 +358,6 @@ extension FetchProvisioningProfilesOperation
}
}
}
-
- internal func fetchProvisioningProfile(for appID: ALTAppID, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void)
- {
- ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
- switch Result(profile, error)
- {
- case .failure(let error): completionHandler(.failure(error))
- case .success(let profile):
-
- // Delete existing profile
- ALTAppleAPI.shared.delete(profile, for: team, session: session) { (success, error) in
- switch Result(success, error)
- {
- case .failure:
- // As of March 20, 2023, the free provisioning profile is re-generated each fetch, and you can no longer delete it.
- // So instead, we just return the fetched profile from above.
- completionHandler(.success(profile))
-
- case .success:
- Logger.sideload.notice("Generating new free provisioning profile for App ID \(appID.bundleIdentifier, privacy: .public).")
-
- // Fetch new provisioning profile
- ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in
- completionHandler(Result(profile, error))
- }
- }
- }
- }
- }
- }
}
class FetchProvisioningProfilesRefreshOperation: FetchProvisioningProfilesOperation, @unchecked Sendable {
@@ -374,8 +374,8 @@ class FetchProvisioningProfilesInstallOperation: FetchProvisioningProfilesOperat
}
// modify Operations are allowed for the app groups and other stuffs
- func fetchProvisioningProfile(appID: ALTAppID,
- for app: ALTApplication,
+ override func fetchProvisioningProfile(for appID: ALTAppID,
+ app: ALTApplication,
team: ALTTeam,
session: ALTAppleAPISession,
completionHandler: @escaping (Result) -> Void)
@@ -396,7 +396,7 @@ class FetchProvisioningProfilesInstallOperation: FetchProvisioningProfilesOperat
case .success(let appID):
// Fetch Provisioning Profile
- super.fetchProvisioningProfile(for: appID, team: team, session: session, completionHandler: completionHandler)
+ super.fetchProvisioningProfile(for: appID, app: app, team: team, session: session, completionHandler: completionHandler)
}
}
}
From df2ffb1235c43bcafdbc0dd7d4b660301cf28dd4 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Tue, 28 Jan 2025 22:37:40 +0530
Subject: [PATCH 07/14] [Roxas]: updated with upstream
---
Dependencies/Roxas | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dependencies/Roxas b/Dependencies/Roxas
index 03f60139..0784711e 160000
--- a/Dependencies/Roxas
+++ b/Dependencies/Roxas
@@ -1 +1 @@
-Subproject commit 03f6013972ff650a7c04c3d6397751c75920b3d8
+Subproject commit 0784711ed9a3a0bdb5cc57bde35d2c621691cf74
From b2184373888c37a108af04130bba7ae627102de4 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Wed, 29 Jan 2025 02:03:17 +0530
Subject: [PATCH 08/14] [Fix]: Throw error only if the popup is not displayed
---
AltStore/Operations/Errors/OperationError.swift | 4 ++--
AltStore/Operations/RemoveAppExtensionsOperation.swift | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/AltStore/Operations/Errors/OperationError.swift b/AltStore/Operations/Errors/OperationError.swift
index 52486a1b..103287e0 100644
--- a/AltStore/Operations/Errors/OperationError.swift
+++ b/AltStore/Operations/Errors/OperationError.swift
@@ -238,10 +238,10 @@ struct OperationError: ALTLocalizedError {
case .invalidParameters:
let message = self._failureReason.map { ": \n\($0)" } ?? "."
- return String(format: NSLocalizedString("Invalid parameters\n%@", comment: ""), message)
+ return String(format: NSLocalizedString("Invalid parameters%@", comment: ""), message)
case .invalidOperationContext:
let message = self._failureReason.map { ": \n\($0)" } ?? "."
- return String(format: NSLocalizedString("Invalid Operation Context\n%@", comment: ""), message)
+ return String(format: NSLocalizedString("Invalid Operation Context%@", comment: ""), message)
case .serverNotFound: return NSLocalizedString("AltServer could not be found.", comment: "")
case .connectionFailed: return NSLocalizedString("A connection to AltServer could not be established.", comment: "")
case .connectionDropped: return NSLocalizedString("The connection to AltServer was dropped.", comment: "")
diff --git a/AltStore/Operations/RemoveAppExtensionsOperation.swift b/AltStore/Operations/RemoveAppExtensionsOperation.swift
index da12500a..f60ce233 100644
--- a/AltStore/Operations/RemoveAppExtensionsOperation.swift
+++ b/AltStore/Operations/RemoveAppExtensionsOperation.swift
@@ -85,7 +85,7 @@ final class RemoveAppExtensionsOperation: ResultOperation
presentingViewController.present(alertController, animated: true){
// if for any reason the view wasn't presented, then just signal that as error
- if presentingViewController.presentedViewController == nil {
+ if presentingViewController.presentedViewController == nil && !alertController.isViewLoaded {
let errMsg = "RemoveAppExtensionsOperation: unable to present dialog, view context not available." +
"\nDid you move to different screen or background after starting the operation?"
self.finish(.failure(
From 803eb615cd0f70f10a8f46df82f1b89629bb8143 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Wed, 29 Jan 2025 02:38:27 +0530
Subject: [PATCH 09/14] [Fix]: VerifyError message was missing version info for
mismatched versions
---
AltStore/Operations/Errors/VerificationError.swift | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/AltStore/Operations/Errors/VerificationError.swift b/AltStore/Operations/Errors/VerificationError.swift
index 3219dfec..635a728d 100644
--- a/AltStore/Operations/Errors/VerificationError.swift
+++ b/AltStore/Operations/Errors/VerificationError.swift
@@ -155,11 +155,11 @@ struct VerificationError: ALTLocalizedError
case .mismatchedVersion:
let appName = self.$app.name ?? NSLocalizedString("the app", comment: "")
- return String(format: NSLocalizedString("The downloaded version of %@ does not match the version specified by the source.", comment: ""), appName)
+ return String(format: NSLocalizedString("The downloaded version of %@ does not match the version specified by the source.\nExpected version: %@\nFound version: %@", comment: ""), appName, expectedVersion ?? "nil", version ?? "nil")
case .mismatchedBuildVersion:
let appName = self.$app.name ?? NSLocalizedString("the app", comment: "")
- return String(format: NSLocalizedString("The downloaded version of %@ does not match the build number specified by the source.", comment: ""), appName)
+ return String(format: NSLocalizedString("The downloaded version of %@ does not match the build number specified by the source.\nExpected version: %@\nFound version: %@", comment: ""), appName, expectedVersion ?? "nil", version ?? "nil")
case .undeclaredPermissions:
let appName = self.$app.name ?? NSLocalizedString("The app", comment: "")
From ac63314a9145251e24ef0e12a2228a3262e8888c Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Sat, 25 Jan 2025 04:36:05 +0530
Subject: [PATCH 10/14] [cleanup]: Disable patrons related stuff as it is
non-functional
---
AltStore/Managing Apps/AppManager.swift | 51 +++++++++++++------------
1 file changed, 27 insertions(+), 24 deletions(-)
diff --git a/AltStore/Managing Apps/AppManager.swift b/AltStore/Managing Apps/AppManager.swift
index 39fc0c47..61c85870 100644
--- a/AltStore/Managing Apps/AppManager.swift
+++ b/AltStore/Managing Apps/AppManager.swift
@@ -593,30 +593,30 @@ extension AppManager
func updatePatronsIfNeeded()
{
- guard self.operationQueue.operations.allSatisfy({ !($0 is UpdatePatronsOperation) }) else {
- // There's already an UpdatePatronsOperation running.
- return
- }
-
- self.updatePatronsResult = nil
-
- let updatePatronsOperation = UpdatePatronsOperation()
- updatePatronsOperation.resultHandler = { (result) in
- do
- {
- try result.get()
- self.updatePatronsResult = .success(())
- }
- catch
- {
- print("Error updating Friend Zone Patrons:", error)
- self.updatePatronsResult = .failure(error)
- }
-
- NotificationCenter.default.post(name: AppManager.didUpdatePatronsNotification, object: self)
- }
-
- self.run([updatePatronsOperation], context: nil)
+// guard self.operationQueue.operations.allSatisfy({ !($0 is UpdatePatronsOperation) }) else {
+// // There's already an UpdatePatronsOperation running.
+// return
+// }
+//
+// self.updatePatronsResult = nil
+//
+// let updatePatronsOperation = UpdatePatronsOperation()
+// updatePatronsOperation.resultHandler = { (result) in
+// do
+// {
+// try result.get()
+// self.updatePatronsResult = .success(())
+// }
+// catch
+// {
+// print("Error updating Friend Zone Patrons:", error)
+// self.updatePatronsResult = .failure(error)
+// }
+//
+// NotificationCenter.default.post(name: AppManager.didUpdatePatronsNotification, object: self)
+// }
+//
+// self.run([updatePatronsOperation], context: nil)
}
func updateAllSources(completion: @escaping (Result) -> Void)
@@ -634,6 +634,9 @@ extension AppManager
do
{
let (_, context) = try result.get()
+// print("\n\n\n\(context.insertedObjects)\n\n\n")
+// print("\n\n\n\(context.updatedObjects)\n\n\n")
+// print("\n\n\n\(context.deletedObjects)\n\n\n")
try context.save()
DispatchQueue.main.async {
From 0245f6072a480c4964b58ad71fd00f32574dbb00 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Sun, 2 Feb 2025 03:37:49 +0530
Subject: [PATCH 11/14] [cleanup]: Sources tab add source storyboard
---
AltStore/Sources/Sources.storyboard | 29 ++++++++++++++---------------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/AltStore/Sources/Sources.storyboard b/AltStore/Sources/Sources.storyboard
index 5782dda2..35cc8703 100644
--- a/AltStore/Sources/Sources.storyboard
+++ b/AltStore/Sources/Sources.storyboard
@@ -13,11 +13,11 @@
-
+
-
+
@@ -33,7 +33,7 @@
-
+
@@ -59,9 +59,9 @@
-
+
-
+
@@ -75,7 +75,7 @@
-
+
@@ -87,7 +87,7 @@
-
+
@@ -95,7 +95,7 @@
-
+
@@ -122,7 +122,7 @@
-
+
@@ -148,7 +148,7 @@
-
+
@@ -160,7 +160,7 @@
-
+
@@ -192,7 +192,7 @@
-
+
@@ -226,7 +226,6 @@
-
@@ -238,10 +237,10 @@
-
+
-
+
From e43e962bcc5e8c8dff21b9ff9d03ad25e088cbb7 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Sun, 2 Feb 2025 03:52:44 +0530
Subject: [PATCH 12/14] [AppIDs-View]: updated header section size
---
AltStore/App IDs/AppIDsViewController.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/AltStore/App IDs/AppIDsViewController.swift b/AltStore/App IDs/AppIDsViewController.swift
index 23e0ab90..83d45f94 100644
--- a/AltStore/App IDs/AppIDsViewController.swift
+++ b/AltStore/App IDs/AppIDsViewController.swift
@@ -195,7 +195,7 @@ extension AppIDsViewController: UICollectionViewDelegateFlowLayout
// NOTE: double dequeue of cell has been discontinued
// TODO: Using harcoded value until this is fixed
- return CGSize(width: collectionView.bounds.width, height: 260)
+ return CGSize(width: collectionView.bounds.width, height: 200)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize
From c3847276f7457bafd83c897e64483b416873a284 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Sun, 2 Feb 2025 04:18:36 +0530
Subject: [PATCH 13/14] [DisableIdleTimeout]: Fix: moved setting
isIdleTimerDisabled = false to AppManager.finish()
---
AltStore/Managing Apps/AppManager.swift | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/AltStore/Managing Apps/AppManager.swift b/AltStore/Managing Apps/AppManager.swift
index 61c85870..13a5927f 100644
--- a/AltStore/Managing Apps/AppManager.swift
+++ b/AltStore/Managing Apps/AppManager.swift
@@ -1235,9 +1235,10 @@ private extension AppManager
UIApplication.shared.isIdleTimerDisabled = UserDefaults.standard.isIdleTimeoutDisableEnabled
}
performAppOperations()
- DispatchQueue.main.schedule {
- UIApplication.shared.isIdleTimerDisabled = false
- }
+ // Moved to self.finish()
+// DispatchQueue.main.schedule {
+// UIApplication.shared.isIdleTimerDisabled = false
+// }
}
return group
@@ -2098,6 +2099,11 @@ private extension AppManager
func finish(_ operation: AppOperation, result: Result, group: RefreshGroup, progress: Progress?)
{
+ // remove disableIdleTimeout
+ DispatchQueue.main.schedule {
+ UIApplication.shared.isIdleTimerDisabled = false
+ }
+
// Must remove before saving installedApp.
if let currentProgress = self.progress(for: operation), currentProgress == progress
{
From ac486a47232b3b4bd3d6838a1a39c7009afe1d67 Mon Sep 17 00:00:00 2001
From: Magesh K <47920326+mahee96@users.noreply.github.com>
Date: Sun, 2 Feb 2025 04:38:46 +0530
Subject: [PATCH 14/14] [DisableIdleTimeout]: Fix: account for concurrency
---
AltStore/Managing Apps/AppManager.swift | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/AltStore/Managing Apps/AppManager.swift b/AltStore/Managing Apps/AppManager.swift
index 13a5927f..8081bc26 100644
--- a/AltStore/Managing Apps/AppManager.swift
+++ b/AltStore/Managing Apps/AppManager.swift
@@ -1231,8 +1231,11 @@ private extension AppManager
}
else
{
- DispatchQueue.main.schedule {
- UIApplication.shared.isIdleTimerDisabled = UserDefaults.standard.isIdleTimeoutDisableEnabled
+ // Disable the idleTimeout
+ if !UIApplication.shared.isIdleTimerDisabled { // accept only once if concurrent
+ DispatchQueue.main.schedule {
+ UIApplication.shared.isIdleTimerDisabled = UserDefaults.standard.isIdleTimeoutDisableEnabled
+ }
}
performAppOperations()
// Moved to self.finish()
@@ -2099,9 +2102,14 @@ private extension AppManager
func finish(_ operation: AppOperation, result: Result, group: RefreshGroup, progress: Progress?)
{
- // remove disableIdleTimeout
- DispatchQueue.main.schedule {
- UIApplication.shared.isIdleTimerDisabled = false
+ // Remove disableIdleTimeout
+ // TODO: This should disable for the last finish() request not the first though for batches
+ // probably if we are in batch mode, we can count expected no of finishes() to arrive
+ // and schedule disabling only on last request by matching it with count.
+ if UIApplication.shared.isIdleTimerDisabled { // accept only once if concurrent
+ DispatchQueue.main.schedule {
+ UIApplication.shared.isIdleTimerDisabled = false
+ }
}
// Must remove before saving installedApp.