diff --git a/StikJIT/StikJITApp.swift b/StikJIT/StikJITApp.swift index 5de642ec..367a508f 100644 --- a/StikJIT/StikJITApp.swift +++ b/StikJIT/StikJITApp.swift @@ -16,6 +16,8 @@ struct HeartbeatApp: App { @State private var isPairing = false @State private var heartBeat = false @State private var error: Int32? = nil + @State private var show_error = false + @State private var error_string = "" @StateObject private var mount = MountingProgress.shared let urls: [String] = [ @@ -23,7 +25,7 @@ struct HeartbeatApp: App { "https://github.com/doronz88/DeveloperDiskImage/raw/refs/heads/main/PersonalizedImages/Xcode_iOS_DDI_Personalized/Image.dmg", "https://github.com/doronz88/DeveloperDiskImage/raw/refs/heads/main/PersonalizedImages/Xcode_iOS_DDI_Personalized/Image.dmg.trustcache" ] - + let outputDir: String = "DDI" let outputFiles: [String] = [ @@ -126,11 +128,23 @@ struct HeartbeatApp: App { for (index, urlString) in urls.enumerated() { let destinationURL = URL.documentsDirectory.appendingPathComponent(outputFiles[index]) if !fileManager.fileExists(atPath: destinationURL.path) { - downloadFile(from: urlString, to: destinationURL) + downloadFile(from: urlString, to: destinationURL){ result in + if (result != ""){ + error_string = "[Download DDI Error]: " + result + show_error = true + } + + } + } } } + .alert("An Error Occurred", isPresented: $show_error) { + Button("OK", role: .cancel) { } + } message: { + Text(error_string) + } } } } @@ -439,19 +453,21 @@ public func showAlert(title: String, message: String, showOk: Bool, showTryAgain } } -func downloadFile(from urlString: String, to destinationURL: URL) { +func downloadFile(from urlString: String, to destinationURL: URL,completion: @escaping (String) -> Void){ let fileManager = FileManager.default let documentsDirectory = URL.documentsDirectory guard let url = URL(string: urlString) else { print("Invalid URL: \(urlString)") + completion("[Internal Invalid URL error]") return } let task = URLSession.shared.downloadTask(with: url) { (tempLocalUrl, response, error) in guard let tempLocalUrl = tempLocalUrl, error == nil else { print("Error downloading file from \(urlString): \(String(describing: error))") + completion("Are you connected to the internet? [Download Failed]") return } @@ -460,10 +476,13 @@ func downloadFile(from urlString: String, to destinationURL: URL) { try fileManager.createDirectory(at: destinationURL.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil) try fileManager.moveItem(at: tempLocalUrl, to: destinationURL) print("Downloaded \(urlString) to \(destinationURL.path)") + } catch { print("Error saving file: \(error)") + } } task.resume() + completion("") } diff --git a/StikJIT/Views/HomeView.swift b/StikJIT/Views/HomeView.swift index dfaeee85..ce6ad27d 100644 --- a/StikJIT/Views/HomeView.swift +++ b/StikJIT/Views/HomeView.swift @@ -15,6 +15,7 @@ extension UIDocumentPickerViewController { } struct HomeView: View { + @Binding var is_lc: Bool @AppStorage("username") private var username = "User" @AppStorage("customBackgroundColor") private var customBackgroundColorHex: String = Color.primaryBackground.toHex() ?? "#000000" @AppStorage("autoQuitAfterEnablingJIT") private var doAutoQuitAfterEnablingJIT = false @@ -32,6 +33,10 @@ struct HomeView: View { @State private var viewDidAppeared = false @State private var pendingBundleIdToEnableJIT : String? = nil + + init(is_lc: Binding? = nil) { + self._is_lc = is_lc ?? .constant(false) + } var body: some View { ZStack { @@ -265,7 +270,9 @@ struct HomeView: View { LogManager.shared.addInfoLog("Starting JIT for \(bundleID)") DispatchQueue.global(qos: .background).async { - let success = JITEnableContext.shared.debugApp(withBundleID: bundleID, logger: { message in + + JITEnableContext.shared().debugApp(withBundleID: bundleID,isLC: is_lc, logger: { message in + if let message = message { // Log messages from the JIT process LogManager.shared.addInfoLog(message) diff --git a/StikJIT/Views/SettingsView.swift b/StikJIT/Views/SettingsView.swift index 8a8a4d16..3cdbc8b3 100644 --- a/StikJIT/Views/SettingsView.swift +++ b/StikJIT/Views/SettingsView.swift @@ -19,6 +19,7 @@ struct SettingsView: View { @State private var pairingFileIsValid = false @State private var isImportingFile = false @State private var importProgress: Float = 0.0 + @State private var is_lc = false @StateObject private var mountProg = MountingProgress.shared @@ -33,7 +34,8 @@ struct SettingsView: View { "Stossy11": "https://github.com/Stossy11.png", "Neo": "https://github.com/neoarz.png", "Se2crid": "https://github.com/Se2crid.png", - "Huge_Black": "https://github.com/HugeBlack.png" + "HugeBlack": "https://github.com/HugeBlack.png", + "Wynwxst": "https://github.com/Wynwxst.png" ] var body: some View { @@ -258,6 +260,21 @@ struct SettingsView: View { self.mounted = isMounted() } } + SettingsCard { + VStack(alignment: .leading, spacing: 20) { + Text("Misclaneous Settings") + .font(.headline) + .foregroundColor(.primary) + .padding(.bottom, 4) + + Toggle("Enable In-LiveContainer JIT", isOn: $is_lc) + .padding() + + HomeView(is_lc: $is_lc) + } + .padding(.vertical, 20) + .padding(.horizontal, 16) + } // About section @@ -342,6 +359,8 @@ struct SettingsView: View { CollaboratorRow(name: "Se2crid", url: "https://github.com/Se2crid", imageUrl: developerProfiles["Se2crid"] ?? "") CollaboratorRow(name: "HugeBlack", url: "https://github.com/HugeBlack", imageUrl: developerProfiles["HugeBlack"] ?? "") + + CollaboratorRow(name: "Wynwxst", url: "https://github.com/Wynwxst", imageUrl: developerProfiles["Wynwxst"] ?? "") } } diff --git a/StikJIT/idevice/JITEnableContext.h b/StikJIT/idevice/JITEnableContext.h index a3d1870d..5928dc66 100644 --- a/StikJIT/idevice/JITEnableContext.h +++ b/StikJIT/idevice/JITEnableContext.h @@ -16,7 +16,7 @@ typedef void (^LogFunc)(NSString *message); @property (class, readonly)JITEnableContext* shared; - (IdevicePairingFile*)getPairingFileWithError:(NSError**)error; - (void)startHeartbeatWithCompletionHandler:(HeartbeatCompletionHandler)completionHandler logger:(LogFunc)logger; -- (BOOL)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger; +- (void)debugAppWithBundleID:(NSString*)bundleID isLC:(BOOL)isLC logger:(LogFunc)logger; - (NSDictionary*)getAppListWithError:(NSError**)error; - (UIImage*)getAppIconWithBundleId:(NSString*)bundleId error:(NSError**)error; @end diff --git a/StikJIT/idevice/JITEnableContext.m b/StikJIT/idevice/JITEnableContext.m index 05a36805..330812d1 100644 --- a/StikJIT/idevice/JITEnableContext.m +++ b/StikJIT/idevice/JITEnableContext.m @@ -104,7 +104,9 @@ - (void)startHeartbeatWithCompletionHandler:(HeartbeatCompletionHandler)completi completionHandler(result,[NSString stringWithCString:message encoding:NSASCIIStringEncoding]); }, [self createCLogger:logger]); } -- (BOOL)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger { + +- (void)debugAppWithBundleID:(NSString*)bundleID isLC:(BOOL)isLC logger:(LogFunc)logger { + if(!provider) { if(logger) { logger(@"Provider not initialized!"); @@ -113,7 +115,10 @@ - (BOOL)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger { return NO; } - return debug_app(provider, [bundleID UTF8String], [self createCLogger:logger]) == 0; + + + return debug_app(provider, [bundleID UTF8String], [self createCLogger:logger], (bool)(isLC)) == 0; + } diff --git a/StikJIT/idevice/jit.c b/StikJIT/idevice/jit.c index b0d109a2..c7cf0ce3 100644 --- a/StikJIT/idevice/jit.c +++ b/StikJIT/idevice/jit.c @@ -18,7 +18,7 @@ #include "jit.h" -int debug_app(TcpProviderHandle* tcp_provider, const char *bundle_id, LogFuncC logger) { +int debug_app(TcpProviderHandle* tcp_provider, const char *bundle_id, LogFuncC logger,bool isLC) { // Initialize logger idevice_init_logger(Debug, Disabled, NULL); IdeviceErrorCode err = IdeviceSuccess; @@ -98,8 +98,10 @@ int debug_app(TcpProviderHandle* tcp_provider, const char *bundle_id, LogFuncC l * Process Control - Launch App *****************************************************************/ logger("=== Launching App ==="); + uint64_t pid; // Get the adapter back from the XPC device + AdapterHandle *pc_adapter = NULL; err = xpc_device_adapter_into_inner(xpc_device, &pc_adapter); if (err != IdeviceSuccess) { @@ -140,21 +142,25 @@ int debug_app(TcpProviderHandle* tcp_provider, const char *bundle_id, LogFuncC l xpc_service_free(debug_service); return 1; } - - // Launch application - uint64_t pid; - err = process_control_launch_app(process_control, bundle_id, NULL, 0, NULL, 0, - true, false, &pid); - if (err != IdeviceSuccess) { - logger("Failed to launch app: %d", err); - process_control_free(process_control); - remote_server_free(remote_server); - xpc_service_free(pc_service); - xpc_service_free(debug_service); - return 1; + if(!isLC){ + + // Launch application + + err = process_control_launch_app(process_control, bundle_id, NULL, 0, NULL, 0, + true, false, &pid); + if (err != IdeviceSuccess) { + logger("Failed to launch app: %d", err); + process_control_free(process_control); + remote_server_free(remote_server); + xpc_service_free(pc_service); + xpc_service_free(debug_service); + return 1; + } + + logger("Successfully launched app with PID: %" PRIu64 "", pid); + } else { + pid = getpid(); } - logger("Successfully launched app with PID: %" PRIu64 "", pid); - // Disable memory limit for PID err = process_control_disable_memory_limit(process_control, pid); if (err != IdeviceSuccess) { diff --git a/StikJIT/idevice/jit.h b/StikJIT/idevice/jit.h index c42f2fc2..8f3b8f38 100644 --- a/StikJIT/idevice/jit.h +++ b/StikJIT/idevice/jit.h @@ -11,6 +11,6 @@ #include "idevice.h" typedef void (^LogFuncC)(const char* message, ...); -int debug_app(TcpProviderHandle* provider, const char *bundle_id, LogFuncC logger); +int debug_app(TcpProviderHandle* provider, const char *bundle_id, LogFuncC logger, bool isLC); #endif /* JIT_H */