From 7c6bdadf3dc1b52fc35548b00648377425ac9b54 Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Sun, 13 Jul 2025 22:59:14 +1000 Subject: [PATCH 1/2] Add URL Scheme for custom app scripts --- .../xcshareddata/swiftpm/Package.resolved | 11 +++- StikJIT/JSSupport/RunJSView.swift | 10 ++- StikJIT/Views/HomeView.swift | 66 ++++++++++++++----- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/StikDebug.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/StikDebug.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7f82837d..165bebd1 100644 --- a/StikDebug.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/StikDebug.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "3675a8b363ad866505239c8e2c7f6a0862ed02618f2dca478b2519372fb79c0c", + "originHash" : "4df9bfc6bef31f016f92a5a4a2b67290e6fd98a0453ec6e1981c9a8fb5222170", "pins" : [ { "identity" : "codeeditorview", @@ -18,6 +18,15 @@ "revision" : "5ff7f3363f7a08f77e0d761e38e6add31c2136e1", "version" : "1.8.1" } + }, + { + "identity" : "swiftui-pipify", + "kind" : "remoteSourceControl", + "location" : "https://github.com/hugeBlack/swiftui-pipify", + "state" : { + "branch" : "main", + "revision" : "a1ec2fd1781c8289bff1a8b3f664dcf21c910efb" + } } ], "version" : 3 diff --git a/StikJIT/JSSupport/RunJSView.swift b/StikJIT/JSSupport/RunJSView.swift index 4b1d11fa..5c97a926 100644 --- a/StikJIT/JSSupport/RunJSView.swift +++ b/StikJIT/JSSupport/RunJSView.swift @@ -23,9 +23,13 @@ class RunJSViewModel: ObservableObject { self.semaphore = semaphore } - func runScript(path: URL) throws { - let scriptContent = try String(contentsOf: path, encoding: .utf8) - scriptName = path.lastPathComponent + func runScript(path: URL, scriptName: String? = nil) throws { + try runScript(data: Data(contentsOf: path), name: scriptName) + } + + func runScript(data: Data, name: String? = nil) throws { + let scriptContent = String(data: data, encoding: .utf8) + scriptName = name ?? "Script" let getPidFunction: @convention(block) () -> Int = { return self.pid diff --git a/StikJIT/Views/HomeView.swift b/StikJIT/Views/HomeView.swift index 918f0238..8454b14d 100644 --- a/StikJIT/Views/HomeView.swift +++ b/StikJIT/Views/HomeView.swift @@ -357,23 +357,29 @@ struct HomeView: View { ) .onOpenURL { url in print(url.path) - if url.host != "enable-jit" { - return - } - - let components = URLComponents(url: url, resolvingAgainstBaseURL: false) - if let bundleId = components?.queryItems?.first(where: { $0.name == "bundle-id" })?.value { - if viewDidAppeared { - startJITInBackground(with: bundleId) - } else { - pendingBundleIdToEnableJIT = bundleId + switch url.host { + case "enable-jit": + let components = URLComponents(url: url, resolvingAgainstBaseURL: false) + if let bundleId = components?.queryItems?.first(where: { $0.name == "bundle-id" })?.value { + if viewDidAppeared { + startJITInBackground(with: bundleId) + } else { + pendingBundleIdToEnableJIT = bundleId + } + } else if let pidStr = components?.queryItems?.first(where: { $0.name == "pid" })?.value, let pid = Int(pidStr) { + if viewDidAppeared { + startJITInBackground(with: pid) + } else { + pendingPIDToEnableJIT = pid + } } - } else if let pidStr = components?.queryItems?.first(where: { $0.name == "pid" })?.value, let pid = Int(pidStr) { - if viewDidAppeared { - startJITInBackground(with: pid) - } else { - pendingPIDToEnableJIT = pid + case "script": + let components = URLComponents(url: url, resolvingAgainstBaseURL: false) + if let script = components?.queryItems?.first(where: { $0.name == "script" })?.value?.data(using: .utf8), let bundleId = components?.queryItems?.first(where: { $0.name == "bundle-id" })?.value { + startJITInBackground(with: bundleId, script: Data(base64Encoded: script)) } + default: + break } } @@ -433,14 +439,34 @@ struct HomeView: View { } } - private func startJITInBackground(with bundleID: String) { + private func getJsCallback(_ script: Data, name: String? = nil) -> DebugAppCallback? { + return { pid, debugProxyHandle, semaphore in + jsModel = RunJSViewModel(pid: Int(pid), debugProxy: debugProxyHandle, semaphore: semaphore) + scriptViewShow = true + DispatchQueue.global(qos: .background).async { + do { + try jsModel?.runScript(data: script, name: name) + isProcessing = false + } catch { + showAlert(title: "Error Occurred While Executing the Default Script.".localized, message: error.localizedDescription, showOk: true) + } + } + } + } + + private func startJITInBackground(with bundleID: String, script: Data? = nil) { isProcessing = true + let orgValue = enablePiP + if script != nil { + enablePiP = true + } // Add log message LogManager.shared.addInfoLog("Starting Debug for \(bundleID)") DispatchQueue.global(qos: .background).async { var callback: DebugAppCallback? = nil + if enableAdvancedOptions { let mapping = UserDefaults.standard.dictionary(forKey: "BundleScriptMap") as? [String: String] if let script = mapping?[bundleID] { @@ -449,6 +475,11 @@ struct HomeView: View { callback = getJsCallback() } } + + if let script { + callback = getJsCallback(script, name: bundleID + ".js") + } + let success = JITEnableContext.shared.debugApp(withBundleID: bundleID, logger: { message in if let message = message { @@ -460,6 +491,9 @@ struct HomeView: View { DispatchQueue.main.async { LogManager.shared.addInfoLog("Debug process completed for \(bundleID)") isProcessing = false + if script != nil { + enablePiP = orgValue + } } } } From b1dd38f8a19673089757d4814a4e833fd47e4452 Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Mon, 14 Jul 2025 12:24:17 +1000 Subject: [PATCH 2/2] add PID and fix script base64 --- StikJIT/Views/HomeView.swift | 57 ++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/StikJIT/Views/HomeView.swift b/StikJIT/Views/HomeView.swift index 8454b14d..569aba00 100644 --- a/StikJIT/Views/HomeView.swift +++ b/StikJIT/Views/HomeView.swift @@ -375,8 +375,19 @@ struct HomeView: View { } case "script": let components = URLComponents(url: url, resolvingAgainstBaseURL: false) - if let script = components?.queryItems?.first(where: { $0.name == "script" })?.value?.data(using: .utf8), let bundleId = components?.queryItems?.first(where: { $0.name == "bundle-id" })?.value { - startJITInBackground(with: bundleId, script: Data(base64Encoded: script)) + if let scriptBase64URL = components?.queryItems?.first(where: { $0.name == "data" })?.value?.removingPercentEncoding, + let bundleId = components?.queryItems?.first(where: { $0.name == "bundle-id" })?.value { + + let base64 = base64URLToBase64(scriptBase64URL) + if let scriptData = Data(base64Encoded: base64) { + startJITInBackground(with: bundleId, script: scriptData) + } + } else if let scriptBase64URL = components?.queryItems?.first(where: { $0.name == "data" })?.value?.removingPercentEncoding, + let pidStr = components?.queryItems?.first(where: { $0.name == "pid" })?.value { + let base64 = base64URLToBase64(scriptBase64URL) + if let scriptData = Data(base64Encoded: base64) { + startJITInBackground(with: Int(pidStr) ?? 0, script: scriptData) + } } default: break @@ -443,6 +454,7 @@ struct HomeView: View { return { pid, debugProxyHandle, semaphore in jsModel = RunJSViewModel(pid: Int(pid), debugProxy: debugProxyHandle, semaphore: semaphore) scriptViewShow = true + DispatchQueue.global(qos: .background).async { do { try jsModel?.runScript(data: script, name: name) @@ -456,18 +468,15 @@ struct HomeView: View { private func startJITInBackground(with bundleID: String, script: Data? = nil) { isProcessing = true - let orgValue = enablePiP - if script != nil { - enablePiP = true - } - // Add log message LogManager.shared.addInfoLog("Starting Debug for \(bundleID)") DispatchQueue.global(qos: .background).async { var callback: DebugAppCallback? = nil - if enableAdvancedOptions { + if let script { + callback = getJsCallback(script, name: bundleID + ".js") + } else if enableAdvancedOptions { let mapping = UserDefaults.standard.dictionary(forKey: "BundleScriptMap") as? [String: String] if let script = mapping?[bundleID] { callback = getJsCallback(for: script) @@ -476,9 +485,6 @@ struct HomeView: View { } } - if let script { - callback = getJsCallback(script, name: bundleID + ".js") - } let success = JITEnableContext.shared.debugApp(withBundleID: bundleID, logger: { message in @@ -491,14 +497,11 @@ struct HomeView: View { DispatchQueue.main.async { LogManager.shared.addInfoLog("Debug process completed for \(bundleID)") isProcessing = false - if script != nil { - enablePiP = orgValue - } } } } - private func startJITInBackground(with pid: Int) { + private func startJITInBackground(with pid: Int, script: Data? = nil) { isProcessing = true // Add log message @@ -506,7 +509,14 @@ struct HomeView: View { DispatchQueue.global(qos: .background).async { - let jsCallback: DebugAppCallback? = (enableAdvancedOptions && useDefaultScript) ? getJsCallback() : nil + var jsCallback: DebugAppCallback? = nil + + if let script { + jsCallback = getJsCallback(script, name: "Script from PID \(pid)") + } else if (enableAdvancedOptions && useDefaultScript) { + jsCallback = getJsCallback() + } + let success = JITEnableContext.shared.debugApp(withPID: Int32(pid), logger: { message in if let message = message { @@ -522,6 +532,21 @@ struct HomeView: View { } } } + + func base64URLToBase64(_ base64url: String) -> String { + var base64 = base64url + .replacingOccurrences(of: "-", with: "+") + .replacingOccurrences(of: "_", with: "/") + + // Pad with "=" to make length a multiple of 4 + let paddingLength = 4 - (base64.count % 4) + if paddingLength < 4 { + base64 += String(repeating: "=", count: paddingLength) + } + + return base64 + } + } class InstalledAppsViewModel: ObservableObject {