diff --git a/StikDebug.xcodeproj/project.pbxproj b/StikDebug.xcodeproj/project.pbxproj index c4c207a..9b88d40 100644 --- a/StikDebug.xcodeproj/project.pbxproj +++ b/StikDebug.xcodeproj/project.pbxproj @@ -542,7 +542,7 @@ "$(PROJECT_DIR)/StikJIT/idevice", ); MACOSX_DEPLOYMENT_TARGET = 15.1; - MARKETING_VERSION = 1.3.1; + MARKETING_VERSION = 1.3.2; PRODUCT_BUNDLE_IDENTIFIER = com.stik.sj; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; @@ -590,7 +590,7 @@ "$(PROJECT_DIR)/StikJIT/idevice", ); MACOSX_DEPLOYMENT_TARGET = 15.1; - MARKETING_VERSION = 1.3.1; + MARKETING_VERSION = 1.3.2; PRODUCT_BUNDLE_IDENTIFIER = com.stik.sj; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; diff --git a/StikJIT/Views/SettingsView.swift b/StikJIT/Views/SettingsView.swift index 930b017..6f7fd58 100644 --- a/StikJIT/Views/SettingsView.swift +++ b/StikJIT/Views/SettingsView.swift @@ -126,7 +126,9 @@ struct SettingsView: View { .font(.headline) .foregroundColor(.primary) .padding(.bottom, 4) - + Toggle("Automatically Quit After Enabling JIT", isOn: $doAutoQuitAfterEnablingJIT) + .foregroundColor(.primary) + .padding(.vertical, 6) Toggle("Skip get-task-allow Check", isOn: $doSkipGetTaskAllowCheck) .foregroundColor(.primary) .padding(.vertical, 6) @@ -427,7 +429,7 @@ struct SettingsView: View { .padding(.bottom, 4) Button(action: { - if let url = URL(string: "") { + if let url = URL(string: "https://github.com/0-Blu/StikDebug-Guide/blob/main/pairing_file.md") { UIApplication.shared.open(url) } }) { @@ -435,7 +437,7 @@ struct SettingsView: View { Image(systemName: "questionmark.circle") .font(.system(size: 18)) .foregroundColor(.primary.opacity(0.8)) - Text("User Manual (Coming Soon)") + Text("Pairing File Guide") .foregroundColor(.primary.opacity(0.8)) Spacer() } diff --git a/StikJIT/idevice/JITEnableContext.m b/StikJIT/idevice/JITEnableContext.m index 8c59c25..807f845 100644 --- a/StikJIT/idevice/JITEnableContext.m +++ b/StikJIT/idevice/JITEnableContext.m @@ -4,6 +4,7 @@ // // Created by s s on 2025/3/28. // + #include "idevice.h" #include #include @@ -13,7 +14,7 @@ #include "applist.h" #include "JITEnableContext.h" -#import "StikDebug-Swift.h" // This imports the Swift files into Objective-C +#import "StikDebug-Swift.h" JITEnableContext* sharedJITContext = nil; @@ -23,7 +24,7 @@ JITEnableContext* sharedJITContext = nil; } + (instancetype)shared { - if(!sharedJITContext) { + if (!sharedJITContext) { sharedJITContext = [[JITEnableContext alloc] init]; } return sharedJITContext; @@ -32,25 +33,25 @@ JITEnableContext* sharedJITContext = nil; - (instancetype)init { NSFileManager* fm = [NSFileManager defaultManager]; NSURL* docPathUrl = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject; - NSURL* pairingFileURL = [docPathUrl URLByAppendingPathComponent:@"idevice_log.txt"]; - idevice_init_logger(Debug, Debug, (char*)pairingFileURL.path.UTF8String); + NSURL* logURL = [docPathUrl URLByAppendingPathComponent:@"idevice_log.txt"]; + idevice_init_logger(Debug, Debug, (char*)logURL.path.UTF8String); return self; } - (NSError*)errorWithStr:(NSString*)str code:(int)code { - return [NSError errorWithDomain:@"StikJIT" code:code userInfo:@{NSLocalizedDescriptionKey: str}]; + return [NSError errorWithDomain:@"StikJIT" + code:code + userInfo:@{ NSLocalizedDescriptionKey: str }]; } - (LogFuncC)createCLogger:(LogFunc)logger { return ^(const char* format, ...) { va_list args; va_start(args, format); - NSString* formatStr = [NSString stringWithCString:format encoding:NSASCIIStringEncoding]; - - NSString *message = [[NSString alloc] initWithFormat:formatStr arguments:args]; + NSString* fmt = [NSString stringWithCString:format encoding:NSASCIIStringEncoding]; + NSString* message = [[NSString alloc] initWithFormat:fmt arguments:args]; NSLog(@"%@", message); - - // Add to log manager + if ([message containsString:@"ERROR"] || [message containsString:@"Error"]) { [[LogManagerBridge shared] addErrorLog:message]; } else if ([message containsString:@"WARNING"] || [message containsString:@"Warning"]) { @@ -60,11 +61,10 @@ JITEnableContext* sharedJITContext = nil; } else { [[LogManagerBridge shared] addInfoLog:message]; } - - if(logger) { + + if (logger) { logger(message); } - va_end(args); }; } @@ -73,12 +73,13 @@ JITEnableContext* sharedJITContext = nil; NSFileManager* fm = [NSFileManager defaultManager]; NSURL* docPathUrl = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject; NSURL* pairingFileURL = [docPathUrl URLByAppendingPathComponent:@"pairingFile.plist"]; - if(![fm fileExistsAtPath:pairingFileURL.path]) { + + if (![fm fileExistsAtPath:pairingFileURL.path]) { NSLog(@"Pairing file not found!"); *error = [self errorWithStr:@"Pairing file not found!" code:-17]; - return false; + return nil; } - + IdevicePairingFile* pairingFile = NULL; IdeviceErrorCode err = idevice_pairing_file_read(pairingFileURL.fileSystemRepresentation, &pairingFile); if (err != IdeviceSuccess) { @@ -88,78 +89,86 @@ JITEnableContext* sharedJITContext = nil; return pairingFile; } -- (void)startHeartbeatWithCompletionHandler:(HeartbeatCompletionHandler)completionHandler logger:(LogFunc)logger { +- (void)startHeartbeatWithCompletionHandler:(HeartbeatCompletionHandler)completionHandler + logger:(LogFunc)logger +{ NSError* err = nil; IdevicePairingFile* pairingFile = [self getPairingFileWithError:&err]; - if(err) { - if(logger) { + if (err) { + // silently swallow “pairing file not found” (-17) + if (err.code == -17) { + return; + } + // for all other errors, log and forward + if (logger) { logger(err.localizedDescription); } - - completionHandler(-17, err.localizedDescription); + completionHandler(err.code, err.localizedDescription); return; } + self->heartbeatSessionId = arc4random(); - startHeartbeat(pairingFile, &(self->provider), &(self->heartbeatSessionId), ^(int result, const char *message) { - completionHandler(result,[NSString stringWithCString:message encoding:NSASCIIStringEncoding]); - }, [self createCLogger:logger]); + startHeartbeat( + pairingFile, + &provider, + &heartbeatSessionId, + ^(int result, const char *message) { + completionHandler(result, + [NSString stringWithCString:message + encoding:NSASCIIStringEncoding]); + }, + [self createCLogger:logger] + ); } -- (BOOL)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger { - - if(!provider) { - if(logger) { +- (BOOL)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger { + if (!provider) { + if (logger) { logger(@"Provider not initialized!"); } NSLog(@"Provider not initialized!"); return NO; } - - - - return debug_app(provider, [bundleID UTF8String], [self createCLogger:logger] ) == 0; - + return debug_app(provider, + [bundleID UTF8String], + [self createCLogger:logger]) == 0; } - -// apps may have different name, so we must use BnudleId as key. [bundleId:name] - (NSDictionary*)getAppListWithError:(NSError**)error { - if(!provider) { + if (!provider) { NSLog(@"Provider not initialized!"); *error = [self errorWithStr:@"Provider not initialized!" code:-1]; return nil; } - + NSString* errorStr = nil; - NSDictionary* ans = list_installed_apps(provider, &errorStr); - if(errorStr){ + NSDictionary* apps = list_installed_apps(provider, &errorStr); + if (errorStr) { *error = [self errorWithStr:errorStr code:-17]; return nil; - } else { - return ans; } + return apps; } - (UIImage*)getAppIconWithBundleId:(NSString*)bundleId error:(NSError**)error { - if(!provider) { + if (!provider) { NSLog(@"Provider not initialized!"); *error = [self errorWithStr:@"Provider not initialized!" code:-1]; return nil; } - + NSString* errorStr = nil; - UIImage* ans = getAppIcon(provider, bundleId, &errorStr); - if(errorStr){ + UIImage* icon = getAppIcon(provider, bundleId, &errorStr); + if (errorStr) { *error = [self errorWithStr:errorStr code:-17]; return nil; - } else { - return ans; } + return icon; } - (void)dealloc { - self->heartbeatSessionId = arc4random(); - if(provider) { + heartbeatSessionId = arc4random(); + if (provider) { tcp_provider_free(provider); } }