Compare commits

..

6 Commits

Author SHA1 Message Date
Huge_Black
75edfad132 Fix AltBackup.ipa is not included
Added a symlink in AltSotore/Resources/AltBackup.ipa that points to build/AltBackup.ipa

It seems Xcode reads all contents in AltSotore/Resources before ipa-altbackup runs, so AltBackup.ipa is missing in the first build. Adding a symlink will cause Xcode to always include that file
2026-03-21 15:30:49 +08:00
Huge_Black
84c5bf40ca Merge pull request #1218 from LiveContainer/develop-lc
Fix widget not working & Only run turn off data shortcut when minimuxer is not ready and below 26.4
2026-03-21 12:08:32 +08:00
Huge_Black
01e73328f8 Only run turn off data shortcut when minimuxer is not ready and below 26.4 2026-03-21 12:01:16 +08:00
Huge_Black
a1f71a8149 Fix widget not working 2026-03-21 11:58:20 +08:00
suprstarrd
8624a8e919 feat: add Mona to Trusted Sources (#1210)
* feat: add Mona to Trusted Sources

Signed-off-by: suprstarrd <business@suprstarrd.com>
2026-03-17 12:28:56 -04:00
ny
6e9e0aee0a fix: revert 26.4 fix partially to fix everywhere 2026-02-28 18:03:35 -05:00
28 changed files with 8501 additions and 1294 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA60C44C93D7A30E3695DD59"
BuildableName = "libem_proxy_static.a"
BlueprintName = "em_proxy-staticlib"
ReferencedContainer = "container:Dependencies/em_proxy.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA60C44C93D7A30E3695DD59"
BuildableName = "libem_proxy_static.a"
BlueprintName = "em_proxy-staticlib"
ReferencedContainer = "container:Dependencies/em_proxy.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA609C732349A560B9642892"
BuildableName = "libminimuxer_static.a"
BlueprintName = "minimuxer-staticlib"
ReferencedContainer = "container:Dependencies/minimuxer.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA609C732349A560B9642892"
BuildableName = "libminimuxer_static.a"
BlueprintName = "minimuxer-staticlib"
ReferencedContainer = "container:Dependencies/minimuxer.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -7,9 +7,6 @@
<FileRef <FileRef
location = "group:Dependencies/AltSign"> location = "group:Dependencies/AltSign">
</FileRef> </FileRef>
<FileRef
location = "group:Dependencies/minimuxer">
</FileRef>
<FileRef <FileRef
location = "group:Dependencies/Roxas/Roxas.xcodeproj"> location = "group:Dependencies/Roxas/Roxas.xcodeproj">
</FileRef> </FileRef>

View File

@@ -12,7 +12,6 @@ import AltStoreCore
import Roxas import Roxas
import Nuke import Nuke
import Minimuxer
class BrowseViewController: UICollectionViewController, PeekPopPreviewing class BrowseViewController: UICollectionViewController, PeekPopPreviewing
{ {

View File

@@ -96,7 +96,7 @@ final class LaunchViewController: UIViewController, UIDocumentPickerDelegate {
try! FileManager.default.removeItem(at: FileManager.default.documentsDirectory.appendingPathComponent(pairingFileName)) try! FileManager.default.removeItem(at: FileManager.default.documentsDirectory.appendingPathComponent(pairingFileName))
displayError("minimuxer failed to start, please restart SideStore. \((error as? LocalizedError)?.failureReason ?? "UNKNOWN ERROR")") displayError("minimuxer failed to start, please restart SideStore. \((error as? LocalizedError)?.failureReason ?? "UNKNOWN ERROR")")
} }
startAutoMounter(documentsDirectory) start_auto_mounter(documentsDirectory)
} }
func fetchPairingFile() -> String? { PairingFileManager.shared.fetchPairingFile(presentingVC: self) } func fetchPairingFile() -> String? { PairingFileManager.shared.fetchPairingFile(presentingVC: self) }

View File

@@ -16,7 +16,6 @@ import WidgetKit
import AltStoreCore import AltStoreCore
import AltSign import AltSign
import Roxas import Roxas
import Minimuxer
extension AppManager extension AppManager
{ {

View File

@@ -701,7 +701,7 @@ private extension AuthenticationOperation
func registerCurrentDevice(for team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTDevice, Error>) -> Void) func registerCurrentDevice(for team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result<ALTDevice, Error>) -> Void)
{ {
guard let udid = fetchUDID() else { guard let udid = fetch_udid()?.toString() else {
return completionHandler(.failure(OperationError.unknownUDID)) return completionHandler(.failure(OperationError.unknownUDID))
} }

View File

@@ -118,7 +118,7 @@ final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result<Inst
if #available(iOS 17, *) { if #available(iOS 17, *) {
// TODO: iOS 17 and above have a new JIT implementation that is completely broken in SideStore :( // TODO: iOS 17 and above have a new JIT implementation that is completely broken in SideStore :(
} else { } else {
startAutoMounter(documentsDirectory) start_auto_mounter(documentsDirectory)
} }
self.managedObjectContext.perform { self.managedObjectContext.perform {

View File

@@ -42,7 +42,7 @@ final class DeactivateAppOperation: ResultOperation<InstalledApp>
for profile in allIdentifiers { for profile in allIdentifiers {
do { do {
try removeProvisioningProfile(profile) try remove_provisioning_profile(profile)
self.progress.completedUnitCount += 1 self.progress.completedUnitCount += 1
installedApp.isActive = false installedApp.isActive = false
self.finish(.success(installedApp)) self.finish(.success(installedApp))

View File

@@ -88,7 +88,7 @@ final class EnableJITOperation<Context: EnableJITContext>: ResultOperation<Void>
var retries = 3 var retries = 3
while (retries > 0){ while (retries > 0){
do { do {
try debugApp(installedApp.resignedBundleIdentifier) try debug_app(installedApp.resignedBundleIdentifier)
self.finish(.success(())) self.finish(.success(()))
retries = 0 retries = 0
} catch { } catch {
@@ -105,7 +105,7 @@ final class EnableJITOperation<Context: EnableJITContext>: ResultOperation<Void>
@available(iOS 17, *) @available(iOS 17, *)
func enableJITSideJITServer(serverURL: URL, installedApp: InstalledApp, completion: @escaping (Result<Void, SideJITServerErrorType>) -> Void) { func enableJITSideJITServer(serverURL: URL, installedApp: InstalledApp, completion: @escaping (Result<Void, SideJITServerErrorType>) -> Void) {
guard let udid = fetchUDID() else { guard let udid = fetch_udid()?.toString() else {
completion(.failure(.other("Unable to get UDID"))) completion(.failure(.other("Unable to get UDID")))
return return
} }

View File

@@ -214,13 +214,11 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default, handler: { _ in alert.addAction(UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default, handler: { _ in
print("Going home") print("Going home")
// Cell Shortcut // Cell Shortcut
if self.context.shouldTurnOffData {
DispatchQueue.main.async{ UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in
// UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in print("Cell OFF Shortcut finished execution.")}
// print("Cell OFF Shortcut finished execution.")
// }
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
} }
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
})) }))
DispatchQueue.main.async { DispatchQueue.main.async {
@@ -236,14 +234,11 @@ final class InstallAppOperation: ResultOperation<InstalledApp>
} }
} }
} }
// Cell Shortcut
DispatchQueue.main.async { if self.context.shouldTurnOffData {
// Cell Shortcut UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in print("Cell OFF Shortcut finished execution.")}
// UIApplication.shared.open(shortcutURLonDelay, options: [:]) { _ in
// print("Cell OFF Shortcut finished execution.")
// }
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
} }
UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
} }
} }

View File

@@ -123,6 +123,8 @@ class InstallAppOperationContext: AppOperationContext
var alternateIconURL: URL? var alternateIconURL: URL?
var shouldTurnOffData: Bool = false
// Non-nil when installing from a source. // Non-nil when installing from a source.
@AsyncManaged @AsyncManaged
var appVersion: AppVersion? var appVersion: AppVersion?

View File

@@ -11,8 +11,6 @@ import AltStoreCore
import AltSign import AltSign
import Roxas import Roxas
import Minimuxer
@objc(RefreshAppOperation) @objc(RefreshAppOperation)
final class RefreshAppOperation: ResultOperation<InstalledApp> final class RefreshAppOperation: ResultOperation<InstalledApp>
{ {
@@ -48,6 +46,7 @@ final class RefreshAppOperation: ResultOperation<InstalledApp>
for p in profiles { for p in profiles {
do { do {
let bytes =
try installProvisioningProfiles(p.value.data) try installProvisioningProfiles(p.value.data)
} catch { } catch {
self.finish(.failure(MinimuxerError.ProfileInstall)) self.finish(.failure(MinimuxerError.ProfileInstall))

View File

@@ -201,7 +201,7 @@ private extension ResignAppOperation
if app.isAltStoreApp if app.isAltStoreApp
{ {
guard let udid = fetchUDID() else { throw OperationError.unknownUDID } guard let udid = fetch_udid()?.toString() as? String else { throw OperationError.unknownUDID }
guard Bundle.main.object(forInfoDictionaryKey: Bundle.Info.devicePairingString) is String else { throw OperationError.unknownUDID } guard Bundle.main.object(forInfoDictionaryKey: Bundle.Info.devicePairingString) is String else { throw OperationError.unknownUDID }
additionalValues[Bundle.Info.devicePairingString] = "<insert pairing file here>" additionalValues[Bundle.Info.devicePairingString] = "<insert pairing file here>"
additionalValues[Bundle.Info.deviceID] = udid additionalValues[Bundle.Info.deviceID] = udid

View File

@@ -8,8 +8,6 @@
import Foundation import Foundation
import Network import Network
import AltStoreCore import AltStoreCore
import Minimuxer
@objc(SendAppOperation) @objc(SendAppOperation)
final class SendAppOperation: ResultOperation<()> final class SendAppOperation: ResultOperation<()>
@@ -44,15 +42,28 @@ final class SendAppOperation: ResultOperation<()>
let fileURL = InstalledApp.refreshedIPAURL(for: app) let fileURL = InstalledApp.refreshedIPAURL(for: app)
print("AFC App `fileURL`: \(fileURL.absoluteString)") print("AFC App `fileURL`: \(fileURL.absoluteString)")
// Wait for Shortcut to Finish Before Proceeding // only when minimuxer is not ready and below 26.4 should we turn off data
DispatchQueue.main.async { if #available(iOS 26.4, *) {
// UIApplication.shared.open(shortcutURLoff, options: [:]) { _ in context.shouldTurnOffData = false
// print("Shortcut finished execution. Proceeding with file transfer.") } else if !isMinimuxerReady {
context.shouldTurnOffData = true
} else {
context.shouldTurnOffData = false
}
if context.shouldTurnOffData {
// Wait for Shortcut to Finish Before Proceeding
UIApplication.shared.open(shortcutURLoff, options: [:]) { _ in
print("Shortcut finished execution. Proceeding with file transfer.")
DispatchQueue.global().async { DispatchQueue.global().async {
self.processFile(at: fileURL, for: app.bundleIdentifier) self.processFile(at: fileURL, for: app.bundleIdentifier)
} }
// } }
} else {
DispatchQueue.global().async {
self.processFile(at: fileURL, for: app.bundleIdentifier)
}
} }
} }

View File

@@ -0,0 +1 @@
../../build/AltBackup.ipa

View File

@@ -0,0 +1,254 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 53;
objects = {
/* Begin PBXBuildFile section */
A8A5B08D2F4C387300572B4A /* em_proxy.h in Sources */ = {isa = PBXBuildFile; fileRef = 9999259129A45319005CF020 /* em_proxy.h */; };
/* End PBXBuildFile section */
/* Begin PBXBuildRule section */
CA6094FFF692AC6C1400ACA8 /* PBXBuildRule */ = {
isa = PBXBuildRule;
compilerSpec = com.apple.compilers.proxy.script;
filePatterns = "*/em_proxy.h";
fileType = pattern.proxy;
inputFiles = (
);
isEditable = 0;
name = "Cargo project build";
outputFiles = (
"$(OBJECT_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME)",
"$(TARGET_BUILD_DIR)/$(FULL_PRODUCT_NAME)",
"$(SRCROOT)/Dependencies/em_proxy/em_proxy.h",
);
script = "# generated with cargo-xcode 1.5.0\n# modified to use prebuilt binaries\n\nset -eu;\n\nBUILT_SRC=\"./em_proxy/$LIB_FILE_NAME.a\"\necho Generating Static lib: $BUILT_SRC\nln -f -- \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\" || cp \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\necho \"$BUILT_SRC -> $TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\n#DEP_FILE_SRC=\"minimuxer/target/${CARGO_XCODE_TARGET_TRIPLE}/release/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\n#if [ -f \"$DEP_FILE_SRC\" ]; then\n# DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n# cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n# echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\n#fi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don't stay around after archs change\n# must match input for LipoScript\n#FILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\n#touch \"$FILE_LIST\"\n#if ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n# echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\n#fi\n";
};
/* End PBXBuildRule section */
/* Begin PBXFileReference section */
9999259129A45319005CF020 /* em_proxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = em_proxy.h; path = em_proxy/em_proxy.h; sourceTree = "<group>"; };
CA60C44C93D7916DE57E6EBD /* libem_proxy_static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libem_proxy_static.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
CA6094FFF69222869D176AE5 /* Products */ = {
isa = PBXGroup;
children = (
CA60C44C93D7916DE57E6EBD /* libem_proxy_static.a */,
);
name = Products;
sourceTree = "<group>";
};
CA6094FFF692D65BC3C892A8 = {
isa = PBXGroup;
children = (
9999259129A45319005CF020 /* em_proxy.h */,
CA6094FFF69222869D176AE5 /* Products */,
);
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
CA60C44C93D7A30E3695DD59 /* em_proxy-staticlib */ = {
isa = PBXNativeTarget;
buildConfigurationList = CA603DD75FB4A30E3695DD59 /* Build configuration list for PBXNativeTarget "em_proxy-staticlib" */;
buildPhases = (
9987603529A4610700818586 /* Fetch prebuilt binaries */,
CA60445C3036A30E3695DD59 /* Sources */,
);
buildRules = (
CA6094FFF692AC6C1400ACA8 /* PBXBuildRule */,
);
dependencies = (
);
name = "em_proxy-staticlib";
productName = libem_proxy_static.a;
productReference = CA60C44C93D7916DE57E6EBD /* libem_proxy_static.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
CA6094FFF692E04653AD465F /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
TargetAttributes = {
CA60C44C93D7A30E3695DD59 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = CA6094FFF69280E02D6C7F57 /* Build configuration list for PBXProject "em_proxy" */;
compatibilityVersion = "Xcode 11.4";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = CA6094FFF692D65BC3C892A8;
productRefGroup = CA6094FFF69222869D176AE5 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
CA60C44C93D7A30E3695DD59 /* em_proxy-staticlib */,
);
};
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
9987603529A4610700818586 /* Fetch prebuilt binaries */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Fetch prebuilt binaries";
outputFileListPaths = (
);
outputPaths = (
./em_proxy/em_proxy.h,
./em_proxy/em_proxy.swift,
"./em_proxy/libem_proxy-ios.a",
"./em_proxy/libem_proxy-sim.a",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "#!bash\npwd\nchmod +x ./fetch-prebuilt.sh \n./fetch-prebuilt.sh em_proxy\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
CA60445C3036A30E3695DD59 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A8A5B08D2F4C387300572B4A /* em_proxy.h in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
CA604DFE779BA30E3695DD59 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CARGO_XCODE_CARGO_DEP_FILE_NAME = libem_proxy.d;
CARGO_XCODE_CARGO_FILE_NAME = libem_proxy.a;
INSTALL_GROUP = "";
INSTALL_MODE_FLAG = "";
INSTALL_OWNER = "";
LIB_FILE_NAME = "";
"LIB_FILE_NAME[sdk=iphoneos*]" = "libem_proxy-ios";
"LIB_FILE_NAME[sdk=iphonesimulator*]" = "libem_proxy-sim";
MACOSX_DEPLOYMENT_TARGET = 11.5;
PRODUCT_NAME = em_proxy_static;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos";
TVOS_DEPLOYMENT_TARGET = 11.5;
};
name = Release;
};
CA609A517351228BE02872F8 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target";
CARGO_XCODE_BUILD_MODE = debug;
CARGO_XCODE_FEATURES = "";
"CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64;
"CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686;
"CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64;
"CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos;
"CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos;
"CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios;
"CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim";
"CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = ios;
"CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin;
CURRENT_PROJECT_VERSION = 0.1;
MARKETING_VERSION = 0.1.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = em_proxy;
SDKROOT = macosx;
SUPPORTS_MACCATALYST = YES;
};
name = Debug;
};
CA609A5173513CC16B37690B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target";
CARGO_XCODE_BUILD_MODE = release;
CARGO_XCODE_FEATURES = "";
"CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64;
"CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686;
"CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64;
"CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos;
"CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos;
"CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios;
"CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim";
"CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = ios;
"CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin;
CURRENT_PROJECT_VERSION = 0.1;
MARKETING_VERSION = 0.1.0;
PRODUCT_NAME = em_proxy;
SDKROOT = macosx;
SUPPORTS_MACCATALYST = YES;
};
name = Release;
};
CA60DE07A83FA30E3695DD59 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CARGO_XCODE_CARGO_DEP_FILE_NAME = libem_proxy.d;
CARGO_XCODE_CARGO_FILE_NAME = libem_proxy.a;
INSTALL_GROUP = "";
INSTALL_MODE_FLAG = "";
INSTALL_OWNER = "";
LIB_FILE_NAME = "";
"LIB_FILE_NAME[sdk=iphoneos*]" = "libem_proxy-ios";
"LIB_FILE_NAME[sdk=iphonesimulator*]" = "libem_proxy-sim";
MACOSX_DEPLOYMENT_TARGET = 11.5;
PRODUCT_NAME = em_proxy_static;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos";
TVOS_DEPLOYMENT_TARGET = 11.5;
};
name = Debug;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
CA603DD75FB4A30E3695DD59 /* Build configuration list for PBXNativeTarget "em_proxy-staticlib" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CA604DFE779BA30E3695DD59 /* Release */,
CA60DE07A83FA30E3695DD59 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CA6094FFF69280E02D6C7F57 /* Build configuration list for PBXProject "em_proxy" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CA609A5173513CC16B37690B /* Release */,
CA609A517351228BE02872F8 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = CA6094FFF692E04653AD465F /* Project object */;
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "2630" LastUpgradeVersion = "2620"
version = "1.7"> version = "1.7">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -15,10 +15,10 @@
buildForAnalyzing = "YES"> buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "A85A51412F4B4532002E2E11" BlueprintIdentifier = "CA60C44C93D7A30E3695DD59"
BuildableName = "libem_proxy_swift.a" BuildableName = "libem_proxy_static.a"
BlueprintName = "em_proxy-swift" BlueprintName = "em_proxy-staticlib"
ReferencedContainer = "container:AltStore.xcodeproj"> ReferencedContainer = "container:em_proxy.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@@ -50,10 +50,10 @@
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "A85A51412F4B4532002E2E11" BlueprintIdentifier = "CA60C44C93D7A30E3695DD59"
BuildableName = "libem_proxy_swift.a" BuildableName = "libem_proxy_static.a"
BlueprintName = "em_proxy-swift" BlueprintName = "em_proxy-staticlib"
ReferencedContainer = "container:AltStore.xcodeproj"> ReferencedContainer = "container:em_proxy.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
</ProfileAction> </ProfileAction>

118
Dependencies/fetch-prebuilt.sh vendored Executable file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env bash
# Ensure we are in Dependencies directory
cd "$(dirname "$0")"
# Detect if Homebrew is in /opt/homebrew (Apple Silicon) or /usr/local (Intel)
if [[ -d "/opt/homebrew" ]]; then
export PATH="/opt/homebrew/bin:$PATH"
elif [[ -d "/usr/local" ]]; then
export PATH="/usr/local/bin:$PATH"
fi
# Check if wget and curl are installed; if not, install them via Homebrew
if ! command -v wget &> /dev/null; then
echo "wget not found, attempting to install via Homebrew..."
if command -v brew &> /dev/null; then
brew install wget
else
echo "Homebrew is not installed. Please install Homebrew and rerun the script."
exit 1
fi
fi
if ! command -v curl &> /dev/null; then
echo "curl not found, attempting to install via Homebrew..."
if command -v brew &> /dev/null; then
brew install curl
else
echo "Homebrew is not installed. Please install Homebrew and rerun the script."
exit 1
fi
fi
check_for_update() {
if [ -f ".skip-prebuilt-fetch-$1" ]; then
echo "Skipping prebuilt fetch for $1 since .skip-prebuilt-fetch-$1 exists. If you are developing $1 alongside SideStore, don't remove this file, or this script will replace your locally built binaries with the ones built by GitHub Actions."
return
fi
if [ ! -f ".last-prebuilt-fetch-$1" ]; then
echo "0,none" > ".last-prebuilt-fetch-$1"
fi
LAST_FETCH=`cat .last-prebuilt-fetch-$1 | perl -n -e '/([0-9]*),([^ ]*)$/ && print $1'`
LAST_COMMIT=`cat .last-prebuilt-fetch-$1 | perl -n -e '/([0-9]*),([^ ]*)$/ && print $2'`
# Check if required library files exist
FORCE_DOWNLOAD=false
if [ ! -f "$1/lib$1-sim.a" ] || [ ! -f "$1/lib$1-ios.a" ]; then
echo "Required libraries missing for $1, forcing download..."
FORCE_DOWNLOAD=true
fi
# Download if:
# 1. Libraries are missing (FORCE_DOWNLOAD), or
# 2. Last fetch was over 1 hour ago, or
# 3. Force flag was passed
if [ "$FORCE_DOWNLOAD" = true ] || [[ $LAST_FETCH -lt $(expr $(date +%s) - 3600) ]] || [[ "$2" == "force" ]]; then
echo "Checking $1 for update"
echo
LATEST_COMMIT=`curl https://api.github.com/repos/SideStore/$1/releases/latest | perl -n -e '/Commit: https:\\/\\/github\\.com\\/[^\\/]*\\/[^\\/]*\\/commit\\/([^"]*)/ && print $1'`
echo
echo "Last commit: $LAST_COMMIT"
echo "Latest commit: $LATEST_COMMIT"
NOT_UPTODATE=false
if [[ "$LAST_COMMIT" != "$LATEST_COMMIT" ]]; then
echo "Found update on the remote: https://api.github.com/repos/SideStore/$1/releases/latest"
NOT_UPTODATE=true
fi
# Download if:
# 1. Libraries are missing (FORCE_DOWNLOAD), or
# 2. New commit is available
if [ "$FORCE_DOWNLOAD" = true ] || [ "$NOT_UPTODATE" = true ] ;then
echo "downloading binaries"
echo
if [[ "$1" != "minimuxer" ]]; then
wget -O "$1/lib$1-sim.a" "https://github.com/SideStore/$1/releases/latest/download/lib$1-sim.a"
wget -O "$1/lib$1-ios.a" "https://github.com/SideStore/$1/releases/latest/download/lib$1-ios.a"
wget -O "$1/$1.h" "https://github.com/SideStore/$1/releases/latest/download/$1.h"
wget -O "$1/$1.swift" "https://github.com/SideStore/$1/releases/latest/download/$1.swift"
echo
else
wget -O "$1/lib$1-sim.a" "https://github.com/SideStore/$1/releases/latest/download/lib$1-sim.a"
wget -O "$1/lib$1-ios.a" "https://github.com/SideStore/$1/releases/latest/download/lib$1-ios.a"
wget -O "$1/generated.zip" "https://github.com/SideStore/$1/releases/latest/download/generated.zip"
echo
echo "Unzipping generated.zip"
cd "$1"
unzip ./generated.zip
cp -v generated/* .
# Remove all files except ones that comes checked-in from minimuxer repository
find generated -type f ! -name 'minimuxer-Bridging-Header.h' ! -name 'minimuxer-helpers.swift' -exec rm -v {} \;
rm generated.zip
rmdir generated/
cd ..
echo "Done"
fi
else
echo "Up-to-date"
fi
echo "$(date +%s),$LATEST_COMMIT" > ".last-prebuilt-fetch-$1"
else
echo "It hasn't been 1 hour and force was not specified, skipping update check for $1"
fi
}
# Allow for Xcode to check minimuxer and em_proxy separately by skipping the update check if the other one is specified as an argument
if [[ "$1" != "em_proxy" ]]; then
check_for_update minimuxer "$1"
if [[ "$1" != "minimuxer" ]]; then
echo
fi
fi
if [[ "$1" != "minimuxer" ]]; then
check_for_update em_proxy "$1"
fi

View File

@@ -0,0 +1,264 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 53;
objects = {
/* Begin PBXBuildFile section */
A8A5B07F2F4C355800572B4A /* minimuxer.h in Sources */ = {isa = PBXBuildFile; fileRef = A8A5B07D2F4C34FF00572B4A /* minimuxer.h */; };
A8A5B0802F4C355800572B4A /* SwiftBridgeCore.h in Sources */ = {isa = PBXBuildFile; fileRef = A8A5B07E2F4C34FF00572B4A /* SwiftBridgeCore.h */; };
/* End PBXBuildFile section */
/* Begin PBXBuildRule section */
CA6012A875F9AC6C1400ACA8 /* PBXBuildRule */ = {
isa = PBXBuildRule;
compilerSpec = com.apple.compilers.proxy.script;
filePatterns = "*/minimuxer.h";
fileType = pattern.proxy;
inputFiles = (
);
isEditable = 0;
name = "Cargo project build";
outputFiles = (
"$(OBJECT_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME)",
"$(TARGET_BUILD_DIR)/$(FULL_PRODUCT_NAME)",
"$(SRCROOT)/Dependencies/minimuxer/minimuxer.h",
);
script = "# generated with cargo-xcode 1.5.0\n# modified to use prebuilt binaries\n\nset -eu;\n\nBUILT_SRC=\"./minimuxer/${LIB_FILE_NAME}.a\"\necho Generating Static lib: $BUILT_SRC\nln -f -- \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\" || cp \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\necho \"$BUILT_SRC -> $TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\n#DEP_FILE_SRC=\"minimuxer/target/${CARGO_XCODE_TARGET_TRIPLE}/release/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\n#if [ -f \"$DEP_FILE_SRC\" ]; then\n# DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n# cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n# echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\n#fi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don't stay around after archs change\n# must match input for LipoScript\n#FILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\n#touch \"$FILE_LIST\"\n#if ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n# echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\n#fi\n";
};
/* End PBXBuildRule section */
/* Begin PBXFileReference section */
A8A5B07D2F4C34FF00572B4A /* minimuxer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = minimuxer.h; path = minimuxer/minimuxer.h; sourceTree = "<group>"; };
A8A5B07E2F4C34FF00572B4A /* SwiftBridgeCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SwiftBridgeCore.h; path = minimuxer/SwiftBridgeCore.h; sourceTree = "<group>"; };
A8A5B09C2F4C454900572B4A /* minimuxer-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "minimuxer-Bridging-Header.h"; path = "minimuxer/minimuxer-Bridging-Header.h"; sourceTree = "<group>"; };
CA609C732349C7AAD9FA67C4 /* libminimuxer_static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libminimuxer_static.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
CA6012A875F922869D176AE5 /* Products */ = {
isa = PBXGroup;
children = (
CA609C732349C7AAD9FA67C4 /* libminimuxer_static.a */,
);
name = Products;
sourceTree = "<group>";
};
CA6012A875F9D65BC3C892A8 = {
isa = PBXGroup;
children = (
A8A5B07D2F4C34FF00572B4A /* minimuxer.h */,
A8A5B07E2F4C34FF00572B4A /* SwiftBridgeCore.h */,
A8A5B09C2F4C454900572B4A /* minimuxer-Bridging-Header.h */,
CA6012A875F922869D176AE5 /* Products */,
);
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
CA609C732349A560B9642892 /* minimuxer-staticlib */ = {
isa = PBXNativeTarget;
buildConfigurationList = CA600589A243A560B9642892 /* Build configuration list for PBXNativeTarget "minimuxer-staticlib" */;
buildPhases = (
9987603629A4611D00818586 /* Fetch prebuilt binaries */,
CA600F638141A560B9642892 /* Sources */,
);
buildRules = (
CA6012A875F9AC6C1400ACA8 /* PBXBuildRule */,
);
dependencies = (
);
name = "minimuxer-staticlib";
productName = libminimuxer_static.a;
productReference = CA609C732349C7AAD9FA67C4 /* libminimuxer_static.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
CA6012A875F9E04653AD465F /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
TargetAttributes = {
CA609C732349A560B9642892 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = CA6012A875F980E02D6C7F57 /* Build configuration list for PBXProject "minimuxer" */;
compatibilityVersion = "Xcode 11.4";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = CA6012A875F9D65BC3C892A8;
productRefGroup = CA6012A875F922869D176AE5 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
CA609C732349A560B9642892 /* minimuxer-staticlib */,
);
};
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
9987603629A4611D00818586 /* Fetch prebuilt binaries */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Fetch prebuilt binaries";
outputFileListPaths = (
);
outputPaths = (
./minimuxer/minimuxer.h,
./minimuxer/SwiftBridgeCore.h,
./minimuxer/minimuxer.swift,
./minimuxer/SwiftBridgeCore.swift,
"./minimuxer/minimuxer-Bridging-Header.h",
"./minimuxer/minimuxer-helpers.swift",
"./minimuxer/libminimuxer-ios.a",
"./minimuxer/libminimuxer-sim.a",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "#!bash\npwd\nchmod +x ./fetch-prebuilt.sh \n./fetch-prebuilt.sh minimuxer\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
CA600F638141A560B9642892 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A8A5B07F2F4C355800572B4A /* minimuxer.h in Sources */,
A8A5B0802F4C355800572B4A /* SwiftBridgeCore.h in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
CA6008D36272A560B9642892 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CARGO_XCODE_CARGO_DEP_FILE_NAME = libminimuxer.d;
CARGO_XCODE_CARGO_FILE_NAME = libminimuxer.a;
INSTALL_GROUP = "";
INSTALL_MODE_FLAG = "";
INSTALL_OWNER = "";
LIB_FILE_NAME = "";
"LIB_FILE_NAME[sdk=iphoneos*]" = "libminimuxer-ios";
"LIB_FILE_NAME[sdk=iphonesimulator*]" = "libminimuxer-sim";
MACOSX_DEPLOYMENT_TARGET = 11.5;
PRODUCT_NAME = minimuxer_static;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos";
TVOS_DEPLOYMENT_TARGET = 11.5;
};
name = Debug;
};
CA602DE9FCEDA560B9642892 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CARGO_XCODE_CARGO_DEP_FILE_NAME = libminimuxer.d;
CARGO_XCODE_CARGO_FILE_NAME = libminimuxer.a;
INSTALL_GROUP = "";
INSTALL_MODE_FLAG = "";
INSTALL_OWNER = "";
LIB_FILE_NAME = "";
"LIB_FILE_NAME[sdk=iphoneos*]" = "libminimuxer-ios";
"LIB_FILE_NAME[sdk=iphonesimulator*]" = "libminimuxer-sim";
MACOSX_DEPLOYMENT_TARGET = 11.5;
PRODUCT_NAME = minimuxer_static;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos";
TVOS_DEPLOYMENT_TARGET = 11.5;
};
name = Release;
};
CA60A20F8EA6228BE02872F8 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target";
CARGO_XCODE_BUILD_MODE = debug;
CARGO_XCODE_FEATURES = "";
"CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64;
"CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686;
"CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64;
"CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos;
"CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos;
"CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios;
"CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim";
"CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = ios;
"CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin;
CURRENT_PROJECT_VERSION = 0.1;
MARKETING_VERSION = 0.1.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = minimuxer;
SDKROOT = macosx;
SUPPORTS_MACCATALYST = YES;
};
name = Debug;
};
CA60A20F8EA63CC16B37690B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target";
CARGO_XCODE_BUILD_MODE = release;
CARGO_XCODE_FEATURES = "";
"CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64;
"CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686;
"CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64;
"CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos;
"CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos;
"CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios;
"CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim";
"CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = ios;
"CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin;
CURRENT_PROJECT_VERSION = 0.1;
MARKETING_VERSION = 0.1.0;
PRODUCT_NAME = minimuxer;
SDKROOT = macosx;
SUPPORTS_MACCATALYST = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
CA600589A243A560B9642892 /* Build configuration list for PBXNativeTarget "minimuxer-staticlib" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CA602DE9FCEDA560B9642892 /* Release */,
CA6008D36272A560B9642892 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CA6012A875F980E02D6C7F57 /* Build configuration list for PBXProject "minimuxer" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CA60A20F8EA63CC16B37690B /* Release */,
CA60A20F8EA6228BE02872F8 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = CA6012A875F9E04653AD465F /* Project object */;
}

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA609C732349A560B9642892"
BuildableName = "libminimuxer_static.a"
BlueprintName = "minimuxer-staticlib"
ReferencedContainer = "container:minimuxer.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CA609C732349A560B9642892"
BuildableName = "libminimuxer_static.a"
BlueprintName = "minimuxer-staticlib"
ReferencedContainer = "container:minimuxer.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -374,8 +374,7 @@ ipa-altbackup: checkPaths copy-altbackup
@echo " Copying from $(ALT_APP_SRC) into $(ALT_APP_PAYLOAD_DST)" @echo " Copying from $(ALT_APP_SRC) into $(ALT_APP_PAYLOAD_DST)"
@cp -R -f "$(ALT_APP_SRC)/." "$(ALT_APP_PAYLOAD_DST)/$(TARGET_NAME)" @cp -R -f "$(ALT_APP_SRC)/." "$(ALT_APP_PAYLOAD_DST)/$(TARGET_NAME)"
@pushd "$(ALT_APP_DST_ARCHIVE)" && zip -r "../../$(ALT_APP_IPA_DST)" Payload || popd @pushd "$(ALT_APP_DST_ARCHIVE)" && zip -r "../../$(ALT_APP_IPA_DST)" Payload || popd
@cp -f "$(ALT_APP_IPA_DST)" AltStore/Resources @echo " IPA created: build/AltBackup.ipa"
@echo " IPA created: AltStore/Resources/AltBackup.ipa"
clean-altbackup: clean-altbackup:
@echo "" @echo ""

132
SideStore/IfManager.swift Normal file
View File

@@ -0,0 +1,132 @@
//
// IfManager.swift
// AltStore
//
// Created by ny on 2/27/26.
// Copyright © 2026 SideStore. All rights reserved.
//
import Foundation
import Network
fileprivate func uti(_ uint: UInt32) -> String? {
var buf = [CChar](repeating: 0, count: Int(NI_MAXHOST))
var addr = in_addr(s_addr: uint.bigEndian)
guard inet_ntop(AF_INET, &addr, &buf, UInt32(INET_ADDRSTRLEN)) != nil,
let str = String(utf8String: buf) else { return nil }
return str
}
fileprivate func socktouint(_ sock: inout sockaddr) -> UInt32 {
var buf = [CChar](repeating: 0, count: Int(NI_MAXHOST))
guard getnameinfo(&sock, socklen_t(sock.sa_len), &buf, socklen_t(buf.count), nil, socklen_t(0), NI_NUMERICHOST) == 0,
let name = String(utf8String: buf) else {
return 0
}
var addr = in_addr()
guard name.withCString({ cString in
inet_pton(AF_INET, cString, &addr)
}) == 1 else { return 0 }
return addr.s_addr.bigEndian
}
public struct NetInfo: Hashable, CustomStringConvertible {
public let name: String
public let hostIP: String
public let destIP: String
public let maskIP: String
private let host: UInt32
private let dest: UInt32
private let mask: UInt32
init(name: String, host: UInt32, dest: UInt32, mask: UInt32) {
self.name = name
self.host = host
self.dest = dest
self.mask = mask
self.hostIP = uti(host) ?? "10.7.0.0"
self.destIP = uti(dest) ?? "10.7.0.1"
self.maskIP = uti(mask) ?? "255.255.255.0"
}
init?(_ ifaddr: ifaddrs) {
guard
let ianame = String(utf8String: ifaddr.ifa_name)
else { return nil }
let host = socktouint(&ifaddr.ifa_addr.pointee)
let dest = socktouint(&ifaddr.ifa_dstaddr.pointee)
let mask = socktouint(&ifaddr.ifa_netmask.pointee)
self.init(name: ianame, host: host, dest: dest, mask: mask)
}
// computed networking values (still numeric internally)
public var minIP: UInt32 { host & mask }
public var maxIP: UInt32 { host | ~mask }
public var minIPString: String { uti(minIP) ?? "nil" }
public var maxIPString: String { uti(maxIP) ?? "nil" }
public var description: String {
"\(name) | ip=\(hostIP) dest=\(destIP) mask=\(maskIP) range=\(minIPString)-\(maxIPString)"
}
}
final class IfManager: Sendable {
public static let shared = IfManager()
nonisolated(unsafe) private(set) var addrs: Set<NetInfo> = Set()
private init() {
self.addrs = IfManager.query()
}
public func query() {
addrs = IfManager.query()
}
private static func query() -> Set<NetInfo> {
var addrs = Set<NetInfo>()
var head: UnsafeMutablePointer<ifaddrs>? = nil
guard getifaddrs(&head) == 0, let first = head else { return addrs }
defer { freeifaddrs(head) }
var cursor: UnsafeMutablePointer<ifaddrs>? = first
while let current = cursor {
// we only want v4 interfaces that aren't loopback and aren't masked 255.255.255.255
let entry = current.pointee
let flags = Int32(entry.ifa_flags)
let isIPv4 = entry.ifa_addr.pointee.sa_family == UInt8(AF_INET)
let isActive = (flags & (IFF_UP | IFF_RUNNING | IFF_LOOPBACK)) == (IFF_UP | IFF_RUNNING)
if isIPv4, isActive, let info = NetInfo(entry), info.maskIP != "255.255.255.255" {
addrs.insert(info)
}
cursor = entry.ifa_next
}
return addrs
}
private var nextLAN: NetInfo? {
addrs.first { $0.name.starts(with: "en") }
}
var nextProbableSideVPN: NetInfo? {
// try old 10.7.0.1 first, then fallback to next v4
// user should only be connected to StosVPN/LocalDevVPN
addrs.first {
$0.hostIP == "10.7.0.1" ||
$0.name.starts(with: "utun")
}
}
var sideVPNPatched: Bool {
nextLAN?.maskIP == nextProbableSideVPN?.maskIP &&
nextLAN?.maxIP == nextProbableSideVPN?.maxIP
}
}

View File

@@ -6,152 +6,88 @@
// //
import Foundation import Foundation
import Minimuxer private import minimuxer
var isMinimuxerReady: Bool { var isMinimuxerReady: Bool {
var result = true
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
print("[SideStore] isMinimuxerReady = true on simulator") print("isMinimuxerReady property is always true on simulator")
return true
#else #else
result = Minimuxer.ready() IfManager.shared.query()
print("[SideStore] isMinimuxerReady = \(result)") if #available(iOS 26.4, *) {
#endif print("Running patched check")
return result return minimuxer.ready() && IfManager.shared.sideVPNPatched
} } else {
return minimuxer.ready()
}
func targetMinimuxerAddress() {
defer { print("[SideStore] targetMinimuxerAddress() completed") }
#if targetEnvironment(simulator)
print("[SideStore] targetMinimuxerAddress() is no-op on simulator")
#else
print("[SideStore] targetMinimuxerAddress() invoked")
Minimuxer.updateUsbMuxdAddr()
#endif #endif
} }
func minimuxerStartWithLogger(_ pairingFile: String, _ logPath: String, _ loggingEnabled: Bool) throws { func minimuxerStartWithLogger(_ pairingFile: String, _ logPath: String, _ loggingEnabled: Bool) throws {
defer { print("[SideStore] minimuxerStartWithLogger(pairingFile, logPath, dest, loggingEnabled) completed") }
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
print("[SideStore] minimuxerStartWithLogger(pairingFile, logPath, loggingEnabled) is no-op on simulator") print("minimuxerStartWithLogger(\(pairingFile), \(logPath), \(loggingEnabled)) is no-op on simulator")
#else #else
// observe network route changes (and update device endpoint from vpn(utun)) print("minimuxerStartWithLogger(\(pairingFile), \(logPath), \(loggingEnabled))")
NetworkObserver.shared.start() try minimuxer.startWithLogger(pairingFile, logPath, loggingEnabled)
#endif
print("[SideStore] minimuxerStartWithLogger(pairingFile, logPath, dest, loggingEnabled) invoked") }
try Minimuxer.startWithLogger(pairingFile: pairingFile,
logPath: logPath, func targetMinimuxerAddress() {
isConsoleLoggingEnabled: loggingEnabled) #if targetEnvironment(simulator)
print("targetMinimuxerAddress() is no-op on simulator")
#else
minimuxer.target_minimuxer_address()
#endif #endif
} }
func installProvisioningProfiles(_ profileData: Data) throws { func installProvisioningProfiles(_ profileData: Data) throws {
defer { print("[SideStore] installProvisioningProfiles(profileData) completed") }
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
print("[SideStore] installProvisioningProfiles(profileData) is no-op on simulator") print("installProvisioningProfiles(\(profileData)) is no-op on simulator")
#else #else
print("[SideStore] installProvisioningProfiles(profileData) invoked") let slice = profileData.toRustByteSlice()
try Minimuxer.installProvisioningProfile(profile: profileData) try minimuxer.install_provisioning_profile(slice.forRust())
#endif #endif
} }
func removeProvisioningProfile(_ id: String) throws {
defer { print("[SideStore] removeProvisioningProfile(id) completed") }
#if targetEnvironment(simulator)
print("[SideStore] removeProvisioningProfile(id) is no-op on simulator")
#else
print("[SideStore] removeProvisioningProfile(id) invoked")
try Minimuxer.removeProvisioningProfile(id: id)
#endif
}
func removeApp(_ bundleId: String) throws { func removeApp(_ bundleId: String) throws {
defer { print("[SideStore] removeApp(bundleId) completed") }
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
print("[SideStore] removeApp(bundleId) is no-op on simulator") print("removeApp(\(bundleId)) is no-op on simulator")
#else #else
print("[SideStore] removeApp(bundleId) invoked") try minimuxer.remove_app(bundleId)
try Minimuxer.removeApp(bundleId: bundleId)
#endif #endif
} }
func yeetAppAFC(_ bundleId: String, _ rawBytes: Data) throws { func yeetAppAFC(_ bundleId: String, _ rawBytes: Data) throws {
defer { print("[SideStore] yeetAppAFC(bundleId, rawBytes) completed") }
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
print("[SideStore] yeetAppAFC(bundleId, rawBytes) is no-op on simulator") print("yeetAppAFC(\(bundleId), \(rawBytes)) is no-op on simulator")
#else #else
print("[SideStore] yeetAppAFC(bundleId, rawBytes) invoked") let slice = rawBytes.toRustByteSlice()
try Minimuxer.yeetAppAfc(bundleId: bundleId, ipaBytes: rawBytes) try minimuxer.yeet_app_afc(bundleId, slice.forRust())
#endif #endif
} }
func installIPA(_ bundleId: String) throws { func installIPA(_ bundleId: String) throws {
defer { print("[SideStore] installIPA(bundleId) completed") }
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
print("[SideStore] installIPA(bundleId) is no-op on simulator") print("installIPA(\(bundleId)) is no-op on simulator")
#else #else
print("[SideStore] installIPA(bundleId) invoked") try minimuxer.install_ipa(bundleId)
try Minimuxer.installIpa(bundleId: bundleId)
#endif #endif
} }
func fetchUDID() -> String? { func fetchUDID() -> String? {
defer { print("[SideStore] fetchUDID() completed") }
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
print("[SideStore] fetchUDID() is no-op on simulator") print("fetchUDID() is no-op on simulator")
return "XXXXX-XXXX-XXXXX-XXXX" return "XXXXX-XXXX-XXXXX-XXXX"
#else #else
print("[SideStore] fetchUDID() invoked") return minimuxer.fetch_udid()?.toString()
return Minimuxer.fetchUDID()
#endif #endif
} }
func debugApp(_ appId: String) throws {
defer { print("[SideStore] debugApp(appId) completed") }
#if targetEnvironment(simulator)
print("[SideStore] debugApp(appId) is no-op on simulator")
#else
print("[SideStore] debugApp(appId) invoked")
try Minimuxer.debugApp(appId: appId)
#endif
}
func attachDebugger(_ pid: UInt32) throws {
defer { print("[SideStore] attachDebugger(pid) completed") }
#if targetEnvironment(simulator)
print("[SideStore] attachDebugger(pid) is no-op on simulator")
#else
print("[SideStore] attachDebugger(pid) invoked")
try Minimuxer.attachDebugger(pid: pid)
#endif
}
func startAutoMounter(_ docsPath: String) {
defer { print("[SideStore] startAutoMounter(docsPath) completed") }
#if targetEnvironment(simulator)
print("[SideStore] startAutoMounter(docsPath) is no-op on simulator")
#else
print("[SideStore] startAutoMounter(docsPath) invoked")
Minimuxer.startAutoMounter(docsPath: docsPath)
#endif
}
func dumpProfiles(_ docsPath: String) throws -> String {
defer { print("[SideStore] dumpProfiles(docsPath) completed") }
#if targetEnvironment(simulator)
print("[SideStore] dumpProfiles(docsPath) is no-op on simulator")
return ""
#else
print("[SideStore] dumpProfiles(docsPath) invoked")
return try Minimuxer.dumpProfiles(docsPath: docsPath)
#endif
}
func setMinimuxerDebug(_ debug: Bool) {
defer { print("[SideStore] setMinimuxerDebug(debug) completed") }
print("[SideStore] setMinimuxerDebug(debug) invoked")
Minimuxer.setDebug(debug)
}
extension MinimuxerError: @retroactive LocalizedError { extension MinimuxerError: @retroactive LocalizedError {
public var failureReason: String? { public var failureReason: String? {
@@ -162,38 +98,41 @@ extension MinimuxerError: @retroactive LocalizedError {
return NSLocalizedString("Unable to connect to the device, make sure LocalDevVPN is enabled and you're connected to Wi-Fi. This could mean an invalid pairing.", comment: "") return NSLocalizedString("Unable to connect to the device, make sure LocalDevVPN is enabled and you're connected to Wi-Fi. This could mean an invalid pairing.", comment: "")
case .PairingFile: case .PairingFile:
return NSLocalizedString("Invalid pairing file. Your pairing file either didn't have a UDID, or it wasn't a valid plist. Please use iloader to replace it.", comment: "") return NSLocalizedString("Invalid pairing file. Your pairing file either didn't have a UDID, or it wasn't a valid plist. Please use iloader to replace it.", comment: "")
case .CreateDebug: case .CreateDebug:
return createService(name: "debug") return self.createService(name: "debug")
case .LookupApps: case .LookupApps:
return getFromDevice(name: "installed apps") return self.getFromDevice(name: "installed apps")
case .FindApp: case .FindApp:
return getFromDevice(name: "path to the app") return self.getFromDevice(name: "path to the app")
case .BundlePath: case .BundlePath:
return getFromDevice(name: "bundle path") return self.getFromDevice(name: "bundle path")
case .MaxPacket: case .MaxPacket:
return setArgument(name: "max packet") return self.setArgument(name: "max packet")
case .WorkingDirectory: case .WorkingDirectory:
return setArgument(name: "working directory") return self.setArgument(name: "working directory")
case .Argv: case .Argv:
return setArgument(name: "argv") return self.setArgument(name: "argv")
case .LaunchSuccess: case .LaunchSuccess:
return getFromDevice(name: "launch success") return self.getFromDevice(name: "launch success")
case .Detach: case .Detach:
return NSLocalizedString("Unable to detach from the app's process", comment: "") return NSLocalizedString("Unable to detach from the app's process", comment: "")
case .Attach: case .Attach:
return NSLocalizedString("Unable to attach to the app's process", comment: "") return NSLocalizedString("Unable to attach to the app's process", comment: "")
case .CreateInstproxy: case .CreateInstproxy:
return createService(name: "instproxy") return self.createService(name: "instproxy")
case .CreateAfc: case .CreateAfc:
return createService(name: "AFC") return self.createService(name: "AFC")
case .RwAfc: case .RwAfc:
return NSLocalizedString("AFC was unable to manage files on the device.", comment: "") return NSLocalizedString("AFC was unable to manage files on the device. Ensure Wi-Fi and LocalDevVPN are connected. If they both are, replace your pairing using iloader.", comment: "")
case .InstallApp(let message): case .InstallApp(let message):
return NSLocalizedString("Unable to install the app: \(message)", comment: "") return NSLocalizedString("Unable to install the app: \(message.toString())", comment: "")
case .UninstallApp: case .UninstallApp:
return NSLocalizedString("Unable to uninstall the app", comment: "") return NSLocalizedString("Unable to uninstall the app", comment: "")
case .CreateMisagent: case .CreateMisagent:
return createService(name: "misagent") return self.createService(name: "misagent")
case .ProfileInstall: case .ProfileInstall:
return NSLocalizedString("Unable to manage profiles on the device", comment: "") return NSLocalizedString("Unable to manage profiles on the device", comment: "")
case .ProfileRemove: case .ProfileRemove:
@@ -232,16 +171,16 @@ extension MinimuxerError: @retroactive LocalizedError {
return NSLocalizedString("Mount failed", comment: "") return NSLocalizedString("Mount failed", comment: "")
} }
} }
fileprivate func createService(name: String) -> String { fileprivate func createService(name: String) -> String {
String(format: NSLocalizedString("Cannot start a %@ server on the device.", comment: ""), name) return String(format: NSLocalizedString("Cannot start a %@ server on the device.", comment: ""), name)
} }
fileprivate func getFromDevice(name: String) -> String { fileprivate func getFromDevice(name: String) -> String {
String(format: NSLocalizedString("Cannot fetch %@ from the device.", comment: ""), name) return String(format: NSLocalizedString("Cannot fetch %@ from the device.", comment: ""), name)
} }
fileprivate func setArgument(name: String) -> String { fileprivate func setArgument(name: String) -> String {
String(format: NSLocalizedString("Cannot set %@ on the device.", comment: ""), name) return String(format: NSLocalizedString("Cannot set %@ on the device.", comment: ""), name)
} }
} }

View File

@@ -75,6 +75,10 @@
{ {
"identifier": "thatstel.la.altsource", "identifier": "thatstel.la.altsource",
"sourceURL": "https://alt.thatstel.la/" "sourceURL": "https://alt.thatstel.la/"
},
{
"identifier": "com.deliacheminot.mona",
"sourceURL": "https://raw.githubusercontent.com/delia-cheminot/mona-hrt/refs/heads/main/ios_source.json"
} }
], ],
"sources": [ "sources": [
@@ -148,6 +152,10 @@
{ {
"identifier": "thatstel.la.altsource", "identifier": "thatstel.la.altsource",
"sourceURL": "https://alt.thatstel.la/" "sourceURL": "https://alt.thatstel.la/"
},
{
"identifier": "com.deliacheminot.mona",
"sourceURL": "https://raw.githubusercontent.com/delia-cheminot/mona-hrt/refs/heads/main/ios_source.json"
} }
] ]
} }