Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StikJIT

An iOS XCFramework that enables JIT for another process over the device's RSD tunnel.

JIT cannot be enabled in-process, since a process that attaches a debugger to itself deadlocks. StikJIT runs in a separate process, attaches a debugserver to the target by PID, enables JIT for it, then detaches. It is self-contained: the idevice FFI and its bundled JIT scripts (universal.js, legacy.js) are bundled inside. The target must have the get-task-allow entitlement.

Use

Because it needs a separate process, you call StikJIT from a small app extension that your app launches and hands the target app's PID to (for example over XPC). StikJIT does not include that extension, its launch, or the pairing file; your app provides those.

The device needs LocalDevVPN connected, and either Wi-Fi or Airplane Mode enabled, before JIT can be enabled or the DDI can be mounted.

Add StikJIT.xcframework to the extension (Embed & Sign), then call it off the main thread:

import StikJIT

try StikJIT.enableJIT(
    targetPID: hostPID,             // process to enable JIT for
    pairingFile: pairingFileURL,    // device pairing file
    progress: { print("[StikJIT] \($0)") }
)

It blocks until done and throws StikJITError on failure. Pass configuration: to override the tunnel endpoint (defaults to 10.7.0.1:49152). Pass script: to select the bundled JS used to drive the JIT-enabling exchange on devices with TXM — .universal (default) or .legacy based on your app's needs.

Developer Disk Image

The device must have the personalized Developer Disk Image (DDI) mounted before JIT can be enabled — enableJIT will fail otherwise. A mount persists until the device reboots, so it only needs to be (re)done once per boot, not on every launch. Mounting has no dependency on the extension process, so it can be done from anywhere in your app (e.g. on launch or in the background) rather than from the same extension that calls enableJIT:

import StikJIT

let paths = DDIPaths.default(in: documentsDirectory)

if try !StikJIT.isDDIMounted(pairingFile: pairingFileURL) {
    try await StikJIT.downloadDDIIfNeeded(to: paths) { fraction, status in
        print("[DDI] \(status) (\(Int(fraction * 100))%)")
    }
    try StikJIT.mountDDI(pairingFile: pairingFileURL, paths: paths) { fraction in
        print("[DDI] mounting \(Int(fraction * 100))%")
    }
}

Ask DeepWiki

Build

xcodegen generate
xcodebuild archive -scheme StikJIT -destination 'generic/platform=iOS' \
  -archivePath build/StikJIT BUILD_LIBRARY_FOR_DISTRIBUTION=YES
xcodebuild -create-xcframework \
  -framework build/StikJIT.xcarchive/Products/Library/Frameworks/StikJIT.framework \
  -output StikJIT.xcframework

License

StikJIT is licensed under the MPL-2.0 (see LICENSE). It uses StikDebug as a reference, with the bundled idevice, universal.js, and legacy.js retaining their own licenses.

About

An iOS XCFramework that enables JIT for another process over the device's RSD tunnel. Based on StikDebug.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages