diff --git a/README.md b/README.md index 20d2ac5..77a72a1 100644 --- a/README.md +++ b/README.md @@ -7,24 +7,17 @@

An on-device debugger/JIT enabler for iOS versions 17.4+ powered by idevice.

-
- - - - - - - - - - - - -
-
+

+   +   +   +   + +
+

## Features -- **JIT:** Enable Just In Time compilation for sideloaded apps that have the `get-task-allow` entitlement. +- **JIT:** Enable Just-In-Time compilation for sideloaded apps that have the `get-task-allow` entitlement. - **App Launching:** Launch every app installed on your device. - **Console:** Live app and system logs. - **Scripts:** Manage automation scripts (mainly used for iOS 26 JIT). @@ -40,7 +33,7 @@

Add AltSource   -Download .ipa +Download .ipa

## Compatibility @@ -69,12 +62,12 @@ StikDebug enables **JIT** for sideloaded apps on iOS 17.4+ without needing a com - Launch LocalDevVPN and enable the VPN. 4. **Enable JIT for an app** - - Launch StikDebug and tapp the `Enable JIT` button. + - Launch StikDebug and tap the `Enable JIT` button. - Select your sideloaded app from the list in StikDebug. **Troubleshooting** - "Connection dropped" or loopback errors → Check iOS version compatibility / beta warnings. -- Heartbeat errors → Ensure that the VPN is on and that you are connecected to Wi-Fi. It may be a pairing file issue. +- Heartbeat errors → Ensure that the VPN is on and that you are connected to Wi-Fi. It may be a pairing file issue. - Pairing file issues → Replace file with device unlocked & trusted. - Still stuck? Join the [Discord](https://discord.gg/ZnNcrRT3M8) with logs/screenshots. @@ -147,13 +140,11 @@ To propose a new feature, open a feature request issue and provide: ### Code Contributions (Best Practices) - Follow normal Swift and SwiftUI style. -- Write clear and easy to understand code. +- Write clear and easy-to-understand code. - Keep your changes consistent with how the project is already set up. - Make sure everything builds and works without errors. We appreciate your time and effort in helping improve this project. -## Code Help -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/StikDebug/stikdebug) ## License StikDebug is licensed under **AGPL-3.0**. See [`LICENSE`](LICENSE) for details. diff --git a/StikDebug.xcodeproj/project.pbxproj b/StikDebug.xcodeproj/project.pbxproj index b48192d..02930a2 100644 --- a/StikDebug.xcodeproj/project.pbxproj +++ b/StikDebug.xcodeproj/project.pbxproj @@ -482,7 +482,7 @@ "$(PROJECT_DIR)/StikDebug/idevice", ); MACOSX_DEPLOYMENT_TARGET = 15.1; - MARKETING_VERSION = 3.1.13; + MARKETING_VERSION = 3.1.15; PRODUCT_BUNDLE_IDENTIFIER = com.stik.stikdebug; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -544,7 +544,7 @@ "$(PROJECT_DIR)/StikDebug/idevice", ); MACOSX_DEPLOYMENT_TARGET = 15.1; - MARKETING_VERSION = 3.1.13; + MARKETING_VERSION = 3.1.15; PRODUCT_BUNDLE_IDENTIFIER = com.stik.stikdebug; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/StikDebug/Device/IdeviceFFIBridge.swift b/StikDebug/Device/IdeviceFFIBridge.swift index 3e1c98e..2c2c805 100644 --- a/StikDebug/Device/IdeviceFFIBridge.swift +++ b/StikDebug/Device/IdeviceFFIBridge.swift @@ -39,7 +39,8 @@ private enum IdeviceBridge { } let code = Int(ffiError.pointee.code) - let message = string(from: ffiError.pointee.message) ?? fallback + let detail = string(from: ffiError.pointee.message) ?? fallback + let message = detail == fallback ? fallback : "\(fallback): \(detail)" idevice_error_free(ffiError) return makeError(domain: domain, code: code, message: message) } @@ -264,45 +265,50 @@ private enum IdeviceBridge { extension JITEnableContext { func isDeveloperDiskImageMounted() throws -> Bool { try IdeviceBridge.withTunnelHandles(for: self) { adapter, handshake in - var installed: UnsafeMutablePointer? - let ffiError = cryptexd_installed_ddi(adapter, handshake, &installed) - let queryError = ffiError.map { - IdeviceBridge.consumeFFIError($0, fallback: "Failed to query installed DDI cryptex") - } - defer { cryptexd_free_installed_cryptex(installed) } - if installed != nil { - return true + var cryptexQuerySucceeded = false + var cryptexQueryError: NSError? + if DeveloperDiskImageService.usesCryptexDDI { + var installed: UnsafeMutablePointer? + defer { cryptexd_free_installed_cryptex(installed) } + if let ffiError = cryptexd_installed_ddi(adapter, handshake, &installed) { + cryptexQueryError = IdeviceBridge.consumeFFIError(ffiError, fallback: "Failed to query installed DDI cryptex") + } else { + cryptexQuerySucceeded = true + if installed != nil { + return true + } + } } - let legacyMounted = (try? IdeviceBridge.withConnectedClient( - fallback: "Failed to connect to image mounter", - missingClientMessage: "Image mounter client was not created", - connect: { image_mounter_connect_rsd(adapter, handshake, $0) }, - cleanup: { image_mounter_free($0) } - ) { client in - var devices: UnsafeMutablePointer? - var deviceCount = 0 - if let error = image_mounter_copy_devices(client, &devices, &deviceCount) { - throw IdeviceBridge.consumeFFIError(error, fallback: "Failed to fetch mounted devices") - } - if let devices { - for index in 0..? + var deviceCount = 0 + if let error = image_mounter_copy_devices(client, &devices, &deviceCount) { + throw IdeviceBridge.consumeFFIError(error, fallback: "Failed to fetch mounted devices") } - idevice_data_free( - UnsafeMutableRawPointer(devices).assumingMemoryBound(to: UInt8.self), - UInt(deviceCount * MemoryLayout.stride) - ) + if let devices { + for index in 0...stride) + ) + } + return deviceCount > 0 } - return deviceCount > 0 - }) ?? false - if legacyMounted { - return true + } catch { + if cryptexQuerySucceeded { + return false + } + throw cryptexQueryError ?? (error as NSError) } - if let queryError { - throw queryError - } - return false } } diff --git a/StikDebug/Device/JITEnableContext.swift b/StikDebug/Device/JITEnableContext.swift index 9a37cf2..d2c65f0 100644 --- a/StikDebug/Device/JITEnableContext.swift +++ b/StikDebug/Device/JITEnableContext.swift @@ -117,7 +117,8 @@ final class JITEnableContext { guard let ffiError else { return makeError(fallback) } - let message = nsString(from: ffiError.pointee.message, fallback: fallback) + let detail = nsString(from: ffiError.pointee.message, fallback: fallback) + let message = detail == fallback ? fallback : "\(fallback): \(detail)" let error = makeError(message, code: Int(ffiError.pointee.code)) idevice_error_free(ffiError) return error @@ -457,22 +458,19 @@ final class JITEnableContext { private func withConnectedRemoteServer( _ body: (OpaquePointer) throws -> T ) throws -> T { - try ensureTunnel() - guard let adapter, let handshake else { - throw makeError("Tunnel is not connected") - } + try withFreshDebugTunnel(hostname: "StikDebugRemoteServer") { adapter, handshake in + var remoteServer: OpaquePointer? + if let ffiError = remote_server_connect_rsd(adapter, handshake, &remoteServer) { + throw error(from: ffiError, fallback: "Failed to connect remote server") + } - var remoteServer: OpaquePointer? - if let ffiError = remote_server_connect_rsd(adapter, handshake, &remoteServer) { - throw error(from: ffiError, fallback: "Failed to connect remote server") - } + guard let remoteServer else { + throw makeError("Remote server handle was not created") + } - guard let remoteServer else { - throw makeError("Remote server handle was not created") + defer { remote_server_free(remoteServer) } + return try body(remoteServer) } - - defer { remote_server_free(remoteServer) } - return try body(remoteServer) } private func withProcessControl( diff --git a/StikDebug/Device/mountDDI.swift b/StikDebug/Device/mountDDI.swift index 61128b5..0716ebb 100644 --- a/StikDebug/Device/mountDDI.swift +++ b/StikDebug/Device/mountDDI.swift @@ -27,6 +27,7 @@ func checkMountStatus() -> MountCheckResult { do { return try JITEnableContext.shared.isDeveloperDiskImageMounted() ? .mounted : .notMounted } catch { + LogManager.shared.addErrorLog("Failed to check DDI mount status: \(error.localizedDescription)") return .unreachable } } diff --git a/StikDebug/Support/AutoScriptAssignments.swift b/StikDebug/Support/AutoScriptAssignments.swift index 4c6934f..57eabd9 100644 --- a/StikDebug/Support/AutoScriptAssignments.swift +++ b/StikDebug/Support/AutoScriptAssignments.swift @@ -23,7 +23,8 @@ extension ScriptStore { "HyperHLE", "Applesauce", "RPCS3", - "AetherPS4" + "AetherPS4", + "Husk" ], resource: ScriptResource(resourceName: "universal", fileName: "universal.js") ), diff --git a/StikDebug/Views/SettingsView.swift b/StikDebug/Views/SettingsView.swift index 871fe31..fc4bc3e 100644 --- a/StikDebug/Views/SettingsView.swift +++ b/StikDebug/Views/SettingsView.swift @@ -7,7 +7,7 @@ import SwiftUI import UIKit private enum SettingsLinks { - static let githubStars = URL(string: "https://github.com/StikDebug/StikDebug/stargazers")! + static let githubStars = URL(string: "https://github.com/StikDebug/StikDebug")! static let pairingFileGuide = URL(string: "https://github.com/StikDebug/StikDebug-Guide/blob/main/pairing_file.md")! static let localDevVPN = URL(string: "https://apps.apple.com/us/app/localdevvpn/id6755608044")! static let discord = URL(string: "https://discord.gg/qahjXNTDwS")!