Skip to content

Commit 5db5f49

Browse files
authored
(WIP) Rewrite parts of the app in Swift and fix iOS 26.4 issues (#358)
* Rewrite parts of the app in Swift and fix iOS 26.4 issues (WIP) * Add more PID stuff * Improve location simulation * whoops
1 parent 789502a commit 5db5f49

43 files changed

Lines changed: 3556 additions & 2579 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

StikDebug.xcodeproj/project.pbxproj

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -448,14 +448,15 @@
448448
CODE_SIGN_IDENTITY = "Apple Development";
449449
CODE_SIGN_STYLE = Automatic;
450450
CURRENT_PROJECT_VERSION = 1;
451-
DEVELOPMENT_TEAM = XXK735HX49;
451+
DEVELOPMENT_TEAM = "";
452452
ENABLE_HARDENED_RUNTIME = YES;
453453
ENABLE_PREVIEWS = YES;
454-
FRAMEWORK_SEARCH_PATHS = (
454+
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
455+
GENERATE_INFOPLIST_FILE = YES;
456+
HEADER_SEARCH_PATHS = (
455457
"$(inherited)",
456-
"$(PROJECT_DIR)/StikJIT/Sources",
458+
"$(PROJECT_DIR)/StikJIT/idevice",
457459
);
458-
GENERATE_INFOPLIST_FILE = YES;
459460
INFOPLIST_FILE = StikJIT/Info.plist;
460461
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
461462
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
@@ -490,7 +491,7 @@
490491
SUPPORTS_MACCATALYST = NO;
491492
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
492493
SWIFT_EMIT_LOC_STRINGS = YES;
493-
SWIFT_OBJC_BRIDGING_HEADER = "StikJIT/StikJIT-Bridging-Header.h";
494+
SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/StikJIT/idevice";
494495
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
495496
SWIFT_VERSION = 5.0;
496497
TARGETED_DEVICE_FAMILY = "1,2";
@@ -509,14 +510,15 @@
509510
CODE_SIGN_IDENTITY = "Apple Development";
510511
CODE_SIGN_STYLE = Automatic;
511512
CURRENT_PROJECT_VERSION = 1;
512-
DEVELOPMENT_TEAM = XXK735HX49;
513+
DEVELOPMENT_TEAM = "";
513514
ENABLE_HARDENED_RUNTIME = YES;
514515
ENABLE_PREVIEWS = YES;
515-
FRAMEWORK_SEARCH_PATHS = (
516+
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
517+
GENERATE_INFOPLIST_FILE = YES;
518+
HEADER_SEARCH_PATHS = (
516519
"$(inherited)",
517-
"$(PROJECT_DIR)/StikJIT/Sources",
520+
"$(PROJECT_DIR)/StikJIT/idevice",
518521
);
519-
GENERATE_INFOPLIST_FILE = YES;
520522
INFOPLIST_FILE = StikJIT/Info.plist;
521523
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
522524
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
@@ -551,7 +553,7 @@
551553
SUPPORTS_MACCATALYST = NO;
552554
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
553555
SWIFT_EMIT_LOC_STRINGS = YES;
554-
SWIFT_OBJC_BRIDGING_HEADER = "StikJIT/StikJIT-Bridging-Header.h";
556+
SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/StikJIT/idevice";
555557
SWIFT_VERSION = 5.0;
556558
TARGETED_DEVICE_FAMILY = "1,2";
557559
XROS_DEPLOYMENT_TARGET = 2.2;

StikJIT/JSSupport/IDeviceJSBridgeDebugProxy.m

Lines changed: 0 additions & 126 deletions
This file was deleted.
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
//
2+
// JSDebugSupport.swift
3+
// StikDebug
4+
//
5+
// Created by Stephen on 2026/3/30.
6+
//
7+
8+
import Foundation
9+
import JavaScriptCore
10+
import idevice
11+
12+
private func jsException(_ message: String, in context: JSContext?) {
13+
guard let context else { return }
14+
context.exception = JSValue(object: message, in: context)
15+
}
16+
17+
private func describeIdeviceError(_ ffiError: UnsafeMutablePointer<IdeviceFfiError>) -> String {
18+
if let message = ffiError.pointee.message {
19+
return "error code \(ffiError.pointee.code), msg \(String(cString: message))"
20+
}
21+
return "error code \(ffiError.pointee.code)"
22+
}
23+
24+
func handleJSContextSendDebugCommand(_ context: JSContext?, _ commandStr: String, _ debugProxy: OpaquePointer?) -> String? {
25+
guard let debugProxy else {
26+
jsException("debug proxy is unavailable", in: context)
27+
return nil
28+
}
29+
30+
guard let command = debugserver_command_new(commandStr, nil, 0) else {
31+
jsException("failed to allocate debugserver command", in: context)
32+
return nil
33+
}
34+
35+
var response: UnsafeMutablePointer<CChar>?
36+
let ffiError = debug_proxy_send_command(debugProxy, command, &response)
37+
debugserver_command_free(command)
38+
39+
if let ffiError {
40+
jsException(describeIdeviceError(ffiError), in: context)
41+
idevice_error_free(ffiError)
42+
if let response {
43+
idevice_string_free(response)
44+
}
45+
return nil
46+
}
47+
48+
defer {
49+
if let response {
50+
idevice_string_free(response)
51+
}
52+
}
53+
54+
guard let response else { return nil }
55+
return String(cString: response)
56+
}
57+
58+
private func hexCharacter(for value: UInt8) -> UInt8 {
59+
if value < 10 {
60+
return value + Character("0").asciiValue!
61+
}
62+
return value + 87
63+
}
64+
65+
private func fillAddress(into buffer: inout [UInt8], at index: Int, address: UInt64) {
66+
let masks: [UInt64] = [
67+
0xf00000000,
68+
0x0f0000000,
69+
0x00f000000,
70+
0x000f00000,
71+
0x0000f0000,
72+
0x00000f000,
73+
0x000000f00,
74+
0x0000000f0,
75+
0x00000000f,
76+
]
77+
78+
for (offset, mask) in masks.enumerated() {
79+
let shift = UInt64((masks.count - 1 - offset) * 4)
80+
let nibble = UInt8((address & mask) >> shift)
81+
buffer[index + offset] = hexCharacter(for: nibble)
82+
}
83+
}
84+
85+
private func writeChecksum(into buffer: inout [UInt8], at startIndex: Int) {
86+
var checksum: UInt8 = 0
87+
var index = startIndex
88+
while buffer[index] != Character("#").asciiValue! {
89+
checksum &+= buffer[index]
90+
index += 1
91+
}
92+
93+
buffer[index + 1] = hexCharacter(for: (checksum & 0xf0) >> 4)
94+
buffer[index + 2] = hexCharacter(for: checksum & 0x0f)
95+
}
96+
97+
private func makeBulkWriteCommands(startAddress: UInt64, pageSize: UInt64) -> [UInt8] {
98+
let commandCount = Int(pageSize >> 14)
99+
var buffer = [UInt8](repeating: 0, count: commandCount * 19)
100+
101+
var currentAddress = startAddress
102+
for commandIndex in 0..<commandCount {
103+
let start = commandIndex * 19
104+
buffer[start + 0] = Character("$").asciiValue!
105+
buffer[start + 1] = Character("M").asciiValue!
106+
fillAddress(into: &buffer, at: start + 2, address: currentAddress)
107+
buffer[start + 11] = Character(",").asciiValue!
108+
buffer[start + 12] = Character("1").asciiValue!
109+
buffer[start + 13] = Character(":").asciiValue!
110+
buffer[start + 14] = Character("6").asciiValue!
111+
buffer[start + 15] = Character("9").asciiValue!
112+
buffer[start + 16] = Character("#").asciiValue!
113+
writeChecksum(into: &buffer, at: start + 1)
114+
currentAddress += 16_384
115+
}
116+
117+
return buffer
118+
}
119+
120+
func handleJITPageWrite(_ context: JSContext?, _ startAddr: UInt64, _ jitPagesSize: UInt64, _ debugProxy: OpaquePointer?) -> String? {
121+
guard let debugProxy else {
122+
jsException("debug proxy is unavailable", in: context)
123+
return nil
124+
}
125+
126+
let commandBuffer = makeBulkWriteCommands(startAddress: startAddr, pageSize: jitPagesSize)
127+
let commandCount = Int(jitPagesSize >> 14)
128+
let commandsPerBatch = 128
129+
130+
for batchStart in stride(from: 0, to: commandCount, by: commandsPerBatch) {
131+
let commandsToSend = min(commandsPerBatch, commandCount - batchStart)
132+
let byteOffset = batchStart * 19
133+
let byteCount = commandsToSend * 19
134+
135+
let ffiError = commandBuffer.withUnsafeBytes { rawBuffer -> UnsafeMutablePointer<IdeviceFfiError>? in
136+
let baseAddress = rawBuffer.bindMemory(to: UInt8.self).baseAddress!
137+
return debug_proxy_send_raw(debugProxy, baseAddress.advanced(by: byteOffset), UInt(byteCount))
138+
}
139+
140+
if let ffiError {
141+
jsException(describeIdeviceError(ffiError), in: context)
142+
idevice_error_free(ffiError)
143+
return nil
144+
}
145+
146+
for _ in 0..<commandsToSend {
147+
var response: UnsafeMutablePointer<CChar>?
148+
let ffiError = debug_proxy_read_response(debugProxy, &response)
149+
if let response {
150+
idevice_string_free(response)
151+
}
152+
if let ffiError {
153+
jsException(describeIdeviceError(ffiError), in: context)
154+
idevice_error_free(ffiError)
155+
return nil
156+
}
157+
}
158+
}
159+
160+
return "OK"
161+
}

StikJIT/JSSupport/JSSupport.h

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)