├── .gitignore ├── LaunchInSafeMode.plist ├── Makefile ├── Source ├── Classes │ ├── LaunchInSafeModeTweak.h │ └── LaunchInSafeModeTweak.m ├── Headers │ ├── BaseBoard │ │ └── BSAuditToken.h │ ├── FrontBoard │ │ ├── FBApplicationInfo.h │ │ ├── FBApplicationProcess.h │ │ ├── FBMutableProcessExecutionContext.h │ │ └── FBSystemService.h │ ├── SpringBoard │ │ ├── SBApplication.h │ │ ├── SBApplicationShortcutMenu.h │ │ └── SBApplicationShortcutStoreManager.h │ ├── SpringBoardServices │ │ └── SBSApplicationShortcutItem.h │ └── SpringBoardUI │ │ ├── SBUIAppIconForceTouchControllerDataProvider.h │ │ └── SBUIAppIconForceTouchShortcutViewController.h ├── Hooks │ ├── BSLaunchdUtilities.x │ ├── FBApplicationProcess.xm │ ├── SBApplicationShortcutMenu.x │ ├── SBApplicationShortcutMenuDelegate.x │ ├── SBApplicationShortcutStoreManager.x │ ├── SBUIAppIconForceTouchController.x │ └── SBUIAppIconForceTouchControllerDataProvider.x └── PreferenceBundle │ ├── LaunchInSafeModeRootListController.h │ ├── LaunchInSafeModeRootListController.m │ ├── Makefile │ ├── Resources │ ├── Info.plist │ ├── LaunchInSafeMode.plist │ ├── github.png │ ├── github@2x.png │ ├── twitter.png │ └── twitter@2x.png │ └── entry.plist └── control /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | .theos 3 | obj/ 4 | packages/ 5 | debs/ 6 | -------------------------------------------------------------------------------- /LaunchInSafeMode.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include $(THEOS)/makefiles/common.mk 2 | 3 | ARCHS = armv7 armv7s arm64 arm64e 4 | TWEAK_NAME = LaunchInSafeMode 5 | 6 | FindFiles = $(foreach ext, c cpp m mm x xm xi xmi, $(wildcard $(1)/*.$(ext))) 7 | LaunchInSafeMode_FILES = Source/Classes/LaunchInSafeModeTweak.m $(call FindFiles, Source/Hooks) 8 | 9 | SUBPROJECTS += Source/PreferenceBundle 10 | 11 | include $(THEOS_MAKE_PATH)/tweak.mk 12 | include $(THEOS_MAKE_PATH)/aggregate.mk 13 | 14 | after-install:: 15 | install.exec "killall -9 SpringBoard" 16 | -------------------------------------------------------------------------------- /Source/Classes/LaunchInSafeModeTweak.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Classes/LaunchInSafeModeTweak.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../Headers/SpringBoardServices/SBSApplicationShortcutItem.h" 11 | 12 | #ifdef DEBUG 13 | #define LaunchInSafeModeLog(str) \ 14 | do { \ 15 | NSString *formattedString = [[NSString alloc] initWithFormat:@"%s " str, __PRETTY_FUNCTION__]; \ 16 | [[LaunchInSafeModeTweak sharedInstance] logString:formattedString]; \ 17 | \ 18 | [formattedString release]; \ 19 | } while (false); 20 | 21 | #define LaunchInSafeModeLogFormat(str, ...) \ 22 | do { \ 23 | NSString *formattedString = [[NSString alloc] initWithFormat:@"%s " str, __PRETTY_FUNCTION__, ##__VA_ARGS__]; \ 24 | [[LaunchInSafeModeTweak sharedInstance] logString:formattedString]; \ 25 | \ 26 | [formattedString release]; \ 27 | } while (false); 28 | #else 29 | #define LaunchInSafeModeLog(str) 30 | #define LaunchInSafeModeLogFormat(str, ...) 31 | #endif 32 | 33 | static NSString *const kLaunchInSafeModeShortcutItemIdentifier = 34 | @"com.inoahdev.launchinsafemode.safemode"; 35 | 36 | @interface LaunchInSafeModeTweak : NSObject 37 | + (instancetype)sharedInstance; 38 | - (BOOL)isEnabled; 39 | 40 | #ifdef DEBUG 41 | - (void)logString:(NSString *)string; 42 | #endif 43 | 44 | @property (nonatomic, strong) NSString *currentBundleIdentifier; 45 | @property (nonatomic, strong) NSNumber *safeModeNumber; 46 | @property (nonatomic, strong) NSMutableDictionary *cachedShortcutItems; 47 | @end 48 | -------------------------------------------------------------------------------- /Source/Classes/LaunchInSafeModeTweak.m: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Classes/LaunchInSafeModeTweak.m 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import "LaunchInSafeModeTweak.h" 10 | 11 | @interface LaunchInSafeModeTweak () 12 | @property (nonatomic, strong) NSDictionary *preferences; 13 | @end 14 | 15 | #ifdef DEBUG 16 | static FILE *logFile = NULL; 17 | #endif 18 | 19 | static CFStringRef applicationID = (__bridge CFStringRef)@"com.inoahdev.launchinsafemode"; 20 | 21 | static void InitializePreferences(NSDictionary **preferences) { 22 | if (CFPreferencesAppSynchronize(applicationID)) { 23 | CFArrayRef keyList = 24 | CFPreferencesCopyKeyList(applicationID, 25 | kCFPreferencesCurrentUser, 26 | kCFPreferencesAnyHost); 27 | 28 | if (keyList) { 29 | *preferences = 30 | (NSDictionary *)CFPreferencesCopyMultiple( 31 | keyList, 32 | applicationID, 33 | kCFPreferencesCurrentUser, 34 | kCFPreferencesAnyHost); 35 | 36 | CFRelease(keyList); 37 | } 38 | } 39 | 40 | if (!*preferences) { 41 | NSNumber *enabledNumber = [[NSNumber alloc] initWithBool:YES]; 42 | *preferences = 43 | [[NSDictionary alloc] initWithObjectsAndKeys:enabledNumber, 44 | @"kEnabled", 45 | nil]; 46 | 47 | [enabledNumber release]; 48 | } 49 | } 50 | 51 | static void LoadPreferences() { 52 | NSDictionary *preferences = nil; 53 | InitializePreferences(&preferences); 54 | 55 | LaunchInSafeModeTweak *tweak = [LaunchInSafeModeTweak sharedInstance]; 56 | LaunchInSafeModeLogFormat(@"Loaded preferences: %@, old: %@", 57 | preferences, 58 | [tweak preferences]); 59 | 60 | [tweak setPreferences:preferences]; 61 | } 62 | 63 | static CFStringRef preferencesChangedNotificationString = 64 | (__bridge CFStringRef)@"iNoahDevLaunchInSafeModePreferencesChangedNotification"; 65 | 66 | @implementation LaunchInSafeModeTweak 67 | + (instancetype)sharedInstance { 68 | static LaunchInSafeModeTweak *sharedInstance = nil; 69 | static dispatch_once_t onceToken; 70 | 71 | dispatch_once(&onceToken, ^{ 72 | sharedInstance = [[LaunchInSafeModeTweak alloc] init]; 73 | 74 | CFNotificationCenterAddObserver( 75 | CFNotificationCenterGetDarwinNotifyCenter(), 76 | NULL, 77 | (CFNotificationCallback)LoadPreferences, 78 | preferencesChangedNotificationString, 79 | NULL, 80 | CFNotificationSuspensionBehaviorDeliverImmediately); 81 | }); 82 | 83 | return sharedInstance; 84 | } 85 | 86 | - (instancetype)init { 87 | if (self = [super init]) { 88 | _cachedShortcutItems = [[NSMutableDictionary alloc] init]; 89 | _currentBundleIdentifier = nil; 90 | _safeModeNumber = [[NSNumber alloc] initWithBool:YES]; 91 | 92 | #ifdef DEBUG 93 | logFile = fopen("/User/LaunchInSafeMode_Logs.txt", "w"); 94 | #endif 95 | 96 | InitializePreferences(&_preferences); 97 | } 98 | 99 | return self; 100 | } 101 | 102 | - (BOOL)isEnabled { 103 | return [[_preferences objectForKey:@"kEnabled"] boolValue]; 104 | } 105 | 106 | #ifdef DEBUG 107 | - (void)logString:(NSString *)string { 108 | if (logFile) { 109 | fprintf(logFile, "%s\n", [string UTF8String]); 110 | fflush(logFile); 111 | } 112 | } 113 | #endif 114 | 115 | - (void)dealloc { 116 | [_cachedShortcutItems release]; 117 | [_safeModeNumber release]; 118 | 119 | #ifdef DEBUG 120 | if (logFile) { 121 | fclose(logFile); 122 | } 123 | #endif 124 | 125 | [_preferences release]; 126 | [super dealloc]; 127 | } 128 | @end 129 | -------------------------------------------------------------------------------- /Source/Headers/BaseBoard/BSAuditToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Headers/BaseBoard/BSAuditToken.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BSAuditToken : NSObject 12 | + (instancetype)tokenForCurrentProcess; 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Headers/FrontBoard/FBApplicationInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Headers/FrontBoard/FBApplicationInfo.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 7/2/18. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FBApplicationInfo : NSObject { 12 | NSString *_bundleIdentifier; 13 | } 14 | @end -------------------------------------------------------------------------------- /Source/Headers/FrontBoard/FBApplicationProcess.h: -------------------------------------------------------------------------------- 1 | // 2 | // Headers/FrontBoard/FBApplicationProcess.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 7/2/18. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import "FBApplicationInfo.h" 10 | 11 | @interface FBApplicationProcess : NSObject 12 | @property (nonatomic, readonly) FBApplicationInfo *applicationInfo; 13 | @end -------------------------------------------------------------------------------- /Source/Headers/FrontBoard/FBMutableProcessExecutionContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // Headers/FrontBoard/FBMutableProcessExecutionContext.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FBMutableProcessExecutionContext : NSObject 12 | - (NSDictionary *)environment; 13 | - (void)setEnvironment:(NSDictionary *)environment; 14 | @end -------------------------------------------------------------------------------- /Source/Headers/FrontBoard/FBSystemService.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Headers/FrontBoard/FBSystemService.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../BaseBoard/BSAuditToken.h" 11 | 12 | @interface FBSystemService : NSObject 13 | + (instancetype)sharedInstance; 14 | - (void)terminateApplication:(NSString *)application forReason:(NSInteger)reason andReport:(BOOL)report withDescription:(NSString *)description source:(BSAuditToken *)source completion:(id)completion; 15 | @end 16 | -------------------------------------------------------------------------------- /Source/Headers/SpringBoard/SBApplication.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Headers/SpringBoard/SBApplication.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SBApplication : NSObject 12 | - (NSString *)bundleIdentifier; 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Headers/SpringBoard/SBApplicationShortcutMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Headers/SpringBoard/SBApplicationShortcutMenu.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SBApplication.h" 11 | 12 | @interface SBApplicationShortcutMenu : NSObject 13 | @property (nonatomic, strong) SBApplication *application; 14 | @end 15 | -------------------------------------------------------------------------------- /Source/Headers/SpringBoard/SBApplicationShortcutStoreManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Headers/SpringBoard/SBApplicationShortcutStoreManager.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SBApplicationShortcutStoreManager : NSObject 12 | + (instancetype)sharedManager; 13 | - (void)setApplicationShortcutItems:(NSArray *)applicationShortcutItems forBundleIdentifier:(NSString *)bundleIdentifier withVersion:(unsigned long long)version; 14 | @end 15 | -------------------------------------------------------------------------------- /Source/Headers/SpringBoardServices/SBSApplicationShortcutItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Headers/SpringBoardServices/SBSApplicationShortcutItem.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SBSApplicationShortcutItem : NSObject 12 | @property (nonatomic, copy) NSString *localizedTitle; 13 | @property (nonatomic, copy) NSString *bundleIdentifierToLaunch; 14 | @property (nonatomic, copy) NSString *type; 15 | @end 16 | -------------------------------------------------------------------------------- /Source/Headers/SpringBoardUI/SBUIAppIconForceTouchControllerDataProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Headers/SpringBoardUI/SBUIAppIconForceTouchControllerDataProvider.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SBUIAppIconForceTouchControllerDataProvider : NSObject 12 | @property (nonatomic, readonly) NSString *applicationBundleIdentifier; 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Headers/SpringBoardUI/SBUIAppIconForceTouchShortcutViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Headers/SpringBoardUI/SBUIAppIconForceTouchShortcutViewController.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SBUIAppIconForceTouchShortcutViewController : NSObject 12 | @end 13 | -------------------------------------------------------------------------------- /Source/Hooks/BSLaunchdUtilities.x: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Hooks/BSLaunchdUtilities.x 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../Classes/LaunchInSafeModeTweak.h" 11 | 12 | %group UptoiOS11 13 | %hook BSLaunchdUtilities 14 | + (BOOL)createJobWithLabel:(NSString *)jobLabel bundleIdentifier:(NSString *)bundleIdentifier path:(NSString *)path containerPath:(NSString *)containerPath arguments:(NSArray *)arguments environment:(NSMutableDictionary *)environment standardOutputPath:(NSString *)standardOutputPath standardErrorPath:(NSString *)standardErrorPath machServices:(NSArray *)machServices threadPriority:(NSInteger)threadPriority waitForDebugger:(BOOL)waitForDebugger denyCreatingOtherJobs:(BOOL)denyCreatingOtherJobs runAtLoad:(BOOL)runAtLoad disableASLR:(BOOL)disableASLR systemApp:(BOOL)systemApp { 15 | LaunchInSafeModeTweak *tweak = [LaunchInSafeModeTweak sharedInstance]; 16 | NSString *currentBundleIdentifier = [tweak currentBundleIdentifier]; 17 | 18 | if (!currentBundleIdentifier) { 19 | LaunchInSafeModeLog(@"currentBundleIdentifier is nil, LaunchInSafeMode shortcut was not invoked"); 20 | return %orig(); 21 | } 22 | 23 | if (![currentBundleIdentifier isEqualToString:bundleIdentifier]) { 24 | LaunchInSafeModeLogFormat(@"currentBundleIdentifier does not match app being launched, currentBundleIdentifier: %@ vs %@", currentBundleIdentifier, bundleIdentifier); 25 | return %orig(); 26 | } 27 | 28 | [tweak setCurrentBundleIdentifier:nil]; 29 | 30 | BOOL environmentShouldBeReleased = NO; 31 | if (![environment isKindOfClass:%c(NSMutableDictionary)]) { 32 | environment = [environment mutableCopy]; 33 | environmentShouldBeReleased = YES; 34 | } 35 | 36 | [environment setObject:[tweak safeModeNumber] forKey:@"_MSSafeMode"]; 37 | LaunchInSafeModeLogFormat(@"Resulting environment for app launched with LaunchInSafeMode: %@", environment); 38 | 39 | BOOL result = %orig(); 40 | if (environmentShouldBeReleased) { 41 | [environment release]; 42 | } 43 | 44 | return result; 45 | } 46 | %end 47 | %end 48 | 49 | %ctor { 50 | if (IS_IOS_OR_OLDER(iOS_10_3)) { 51 | %init(UptoiOS11); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Source/Hooks/FBApplicationProcess.xm: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Hooks/BKSProcess.x 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../Classes/LaunchInSafeModeTweak.h" 11 | 12 | #import "../Headers/FrontBoard/FBMutableProcessExecutionContext.h" 13 | #import "../Headers/FrontBoard/FBApplicationProcess.h" 14 | 15 | %group iOS11Up 16 | %hook FBApplicationProcess 17 | - (BOOL)_queue_bootstrapAndExecWithContext:(FBMutableProcessExecutionContext *)context { 18 | LaunchInSafeModeTweak *tweak = [LaunchInSafeModeTweak sharedInstance]; 19 | NSString *currentBundleIdentifier = [tweak currentBundleIdentifier]; 20 | 21 | if (!currentBundleIdentifier) { 22 | LaunchInSafeModeLog(@"currentBundleIdentifier is nil, LaunchInSafeMode shortcut was not invoked"); 23 | return %orig(); 24 | } 25 | 26 | FBApplicationInfo *applicationInfo = [self applicationInfo]; 27 | NSString *bundleIdentifier = MSHookIvar(applicationInfo, "_bundleIdentifier"); 28 | 29 | if (![currentBundleIdentifier isEqualToString:bundleIdentifier]) { 30 | LaunchInSafeModeLogFormat(@"currentBundleIdentifier does not match app being launched, currentBundleIdentifier: %@ vs %@", currentBundleIdentifier, bundleIdentifier); 31 | return %orig(); 32 | } 33 | 34 | [tweak setCurrentBundleIdentifier:nil]; 35 | 36 | NSDictionary *environment = [context environment]; 37 | NSMutableDictionary *mutableEnvironment = [environment mutableCopy]; 38 | 39 | [mutableEnvironment setObject:[tweak safeModeNumber] forKey:@"_MSSafeMode"]; 40 | [context setEnvironment:mutableEnvironment]; 41 | 42 | [mutableEnvironment release]; 43 | 44 | LaunchInSafeModeLogFormat(@"Resulting environment for app launched with LaunchInSafeMode: %@", 45 | [context environment]); 46 | return %orig(); 47 | } 48 | %end 49 | %end 50 | 51 | %ctor { 52 | if (IS_IOS_OR_NEWER(iOS_11_0)) { 53 | %init(iOS11Up); 54 | } 55 | } -------------------------------------------------------------------------------- /Source/Hooks/SBApplicationShortcutMenu.x: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Hooks/SBApplicationShortcutMenu.x 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "../Classes/LaunchInSafeModeTweak.h" 12 | #import "../Headers/SpringBoard/SBApplicationShortcutMenu.h" 13 | 14 | %group iOS9 15 | %hook SBApplicationShortcutMenu 16 | - (NSArray *)_shortcutItemsToDisplay { 17 | LaunchInSafeModeTweak *tweak = [LaunchInSafeModeTweak sharedInstance]; 18 | NSMutableArray *originalShortcutItems = (NSMutableArray *)%orig(); 19 | 20 | BOOL isEnabled = [tweak isEnabled]; 21 | if (!isEnabled) { 22 | LaunchInSafeModeLog(@"Tweak is not enabled"); 23 | return originalShortcutItems; 24 | } 25 | 26 | SBApplication *application = [self application]; 27 | NSString *bundleIdentifier = [application bundleIdentifier]; 28 | 29 | NSMutableDictionary *cachedShortcutItems = [tweak cachedShortcutItems]; 30 | SBSApplicationShortcutItem *shortcutItem = 31 | [cachedShortcutItems objectForKey:bundleIdentifier]; 32 | 33 | if (!shortcutItem) { 34 | shortcutItem = [[%c(SBSApplicationShortcutItem) alloc] init]; 35 | 36 | [shortcutItem setLocalizedTitle:@"Safe Mode"]; 37 | [shortcutItem setBundleIdentifierToLaunch:bundleIdentifier]; 38 | [shortcutItem setType:kLaunchInSafeModeShortcutItemIdentifier]; 39 | 40 | [cachedShortcutItems setObject:shortcutItem forKey:bundleIdentifier]; 41 | [shortcutItem release]; 42 | } 43 | 44 | if (![originalShortcutItems isKindOfClass:%c(NSMutableArray)]) { 45 | NSMutableArray *newShortcutItems = [originalShortcutItems mutableCopy]; 46 | [newShortcutItems addObject:shortcutItem]; 47 | 48 | LaunchInSafeModeLogFormat(@"newShortcutItems: %@", newShortcutItems); 49 | return [newShortcutItems autorelease]; 50 | } 51 | 52 | [originalShortcutItems addObject:shortcutItem]; 53 | 54 | LaunchInSafeModeLogFormat(@"originalShortcutItems: %@", originalShortcutItems); 55 | return originalShortcutItems; 56 | } 57 | 58 | %end 59 | %end 60 | 61 | %ctor { 62 | if (IS_IOS_BETWEEN(iOS_9_0, iOS_9_3)) { 63 | %init(iOS9); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Source/Hooks/SBApplicationShortcutMenuDelegate.x: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Hooks/SBApplicationShortcutMenu.x 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../Classes/LaunchInSafeModeTweak.h" 11 | 12 | #import "../Headers/BaseBoard/BSAuditToken.h" 13 | #import "../Headers/FrontBoard/FBSystemService.h" 14 | #import "../Headers/SpringBoard/SBApplicationShortcutMenu.h" 15 | 16 | %group iOS9 17 | %hook SBApplicationShortcutMenuDelegate 18 | - (void)applicationShortcutMenu:(SBApplicationShortcutMenu *)applicationShortcutMenu activateShortcutItem:(SBSApplicationShortcutItem *)shortcutItem index:(NSUInteger)index { 19 | NSString *shortcutItemType = [shortcutItem type]; 20 | if (![shortcutItemType isEqualToString:kLaunchInSafeModeShortcutItemIdentifier]) { 21 | LaunchInSafeModeLogFormat(@"did not invoke LaunchInSafeMode shortcut, invoked shortcut with \"type\": %@", shortcutItemType); 22 | return %orig(); 23 | } 24 | 25 | LaunchInSafeModeTweak *tweak = [LaunchInSafeModeTweak sharedInstance]; 26 | 27 | NSString *bundleIdentifier = [shortcutItem bundleIdentifierToLaunch]; 28 | [tweak setCurrentBundleIdentifier:bundleIdentifier]; 29 | 30 | BSAuditToken *token = [%c(BSAuditToken)tokenForCurrentProcess]; 31 | [[%c(FBSystemService) sharedInstance] terminateApplication:bundleIdentifier 32 | forReason:1 33 | andReport:NO 34 | withDescription:nil 35 | source:token 36 | completion:nil]; 37 | 38 | %orig(); 39 | } 40 | 41 | %end 42 | %end 43 | 44 | %ctor { 45 | if (IS_IOS_BETWEEN(iOS_9_0, iOS_9_3)) { 46 | %init(iOS9); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Source/Hooks/SBApplicationShortcutStoreManager.x: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Hooks/SBApplicationShortcutStoreManager.x 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 6/29/18. 6 | // Copyright © 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../Classes/LaunchInSafeModeTweak.h" 11 | 12 | %group iOS9Up 13 | %hook SBApplicationShortcutStoreManager 14 | - (void)_installedAppsDidChange:(NSNotification *)notification { 15 | NSDictionary *userInfo = [notification userInfo]; 16 | NSSet *removedBundleIdentifiers = 17 | [userInfo objectForKey:@"SBInstalledApplicationsRemovedBundleIDs"]; 18 | 19 | if (removedBundleIdentifiers) { 20 | LaunchInSafeModeTweak *tweak = [LaunchInSafeModeTweak sharedInstance]; 21 | NSMutableDictionary *cachedShortcutItems = [tweak cachedShortcutItems]; 22 | 23 | for (NSString *removedBundleIdentifier in removedBundleIdentifiers) { 24 | [cachedShortcutItems removeObjectForKey:removedBundleIdentifier]; 25 | } 26 | } 27 | 28 | %orig(); 29 | } 30 | %end 31 | %end 32 | 33 | %ctor { 34 | if (IS_IOS_OR_NEWER(iOS_9_0)) { 35 | %init(iOS9Up); 36 | } 37 | } -------------------------------------------------------------------------------- /Source/Hooks/SBUIAppIconForceTouchController.x: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Hooks/SBUIAppIconForceTouchController.x 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../Classes/LaunchInSafeModeTweak.h" 11 | 12 | #import "../Headers/FrontBoard/FBSystemService.h" 13 | #import "../Headers/SpringBoardUI/SBUIAppIconForceTouchShortcutViewController.h" 14 | 15 | %group iOS10Up 16 | %hook SBUIAppIconForceTouchController 17 | - (void)appIconForceTouchShortcutViewController:(SBUIAppIconForceTouchShortcutViewController *)shortcutViewController activateApplicationShortcutItem:(SBSApplicationShortcutItem *)shortcutItem { 18 | NSString *shortcutItemType = [shortcutItem type]; 19 | if (![shortcutItemType isEqualToString:kLaunchInSafeModeShortcutItemIdentifier]) { 20 | LaunchInSafeModeLogFormat(@"did not invoke LaunchInSafeMode shortcut, invoked shortcut with \"type\": %@", shortcutItemType); 21 | return %orig(); 22 | } 23 | 24 | LaunchInSafeModeTweak *tweak = [LaunchInSafeModeTweak sharedInstance]; 25 | 26 | NSString *bundleIdentifier = [shortcutItem bundleIdentifierToLaunch]; 27 | [tweak setCurrentBundleIdentifier:bundleIdentifier]; 28 | 29 | BSAuditToken *token = [%c(BSAuditToken)tokenForCurrentProcess]; 30 | [[%c(FBSystemService) sharedInstance] terminateApplication:bundleIdentifier 31 | forReason:1 32 | andReport:NO 33 | withDescription:nil 34 | source:token 35 | completion:nil]; 36 | 37 | %orig(); 38 | } 39 | 40 | %end 41 | %end 42 | 43 | %ctor { 44 | if (IS_IOS_OR_NEWER(iOS_10_0)) { 45 | %init(iOS10Up); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/Hooks/SBUIAppIconForceTouchControllerDataProvider.x: -------------------------------------------------------------------------------- 1 | // 2 | // Source/Hooks/SBApplicationShortcutStoreManager.x 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "../Classes/LaunchInSafeModeTweak.h" 11 | 12 | #import "../Headers/SpringBoardServices/SBSApplicationShortcutItem.h" 13 | #import "../Headers/SpringBoardUI/SBUIAppIconForceTouchControllerDataProvider.h" 14 | 15 | %group iOS10Up 16 | %hook SBUIAppIconForceTouchControllerDataProvider 17 | - (NSArray *)applicationShortcutItems { 18 | LaunchInSafeModeTweak *tweak = [LaunchInSafeModeTweak sharedInstance]; 19 | NSMutableArray *originalShortcutItems = (NSMutableArray *)%orig(); 20 | 21 | BOOL isEnabled = [tweak isEnabled]; 22 | if (!isEnabled) { 23 | LaunchInSafeModeLog(@"tweak is not enabled"); 24 | return originalShortcutItems; 25 | } 26 | 27 | NSMutableDictionary *cachedShortcutItems = [tweak cachedShortcutItems]; 28 | NSString *bundleIdentifier = [self applicationBundleIdentifier]; 29 | 30 | if (!bundleIdentifier || ![bundleIdentifier isKindOfClass:%c(NSString)]) { 31 | LaunchInSafeModeLogFormat(@"bundleIdentifier is invalid, %@", bundleIdentifier); 32 | return originalShortcutItems; 33 | } 34 | 35 | SBSApplicationShortcutItem *shortcutItem = 36 | [cachedShortcutItems objectForKey:bundleIdentifier]; 37 | 38 | if (!shortcutItem) { 39 | shortcutItem = [[%c(SBSApplicationShortcutItem) alloc] init]; 40 | 41 | [shortcutItem setLocalizedTitle:@"Safe Mode"]; 42 | [shortcutItem setBundleIdentifierToLaunch:bundleIdentifier]; 43 | [shortcutItem setType:kLaunchInSafeModeShortcutItemIdentifier]; 44 | 45 | [cachedShortcutItems setObject:shortcutItem forKey:bundleIdentifier]; 46 | [shortcutItem release]; 47 | } 48 | 49 | if (![originalShortcutItems isKindOfClass:%c(NSMutableArray)]) { 50 | NSMutableArray *newShortcutItems = [originalShortcutItems mutableCopy]; 51 | [newShortcutItems addObject:shortcutItem]; 52 | 53 | LaunchInSafeModeLogFormat(@"newShortcutItems: %@", newShortcutItems); 54 | return [newShortcutItems autorelease]; 55 | } 56 | 57 | [originalShortcutItems addObject:shortcutItem]; 58 | 59 | LaunchInSafeModeLogFormat(@"originalShortcutItems: %@", originalShortcutItems); 60 | return originalShortcutItems; 61 | } 62 | 63 | %end 64 | %end 65 | 66 | %ctor { 67 | if (IS_IOS_OR_NEWER(iOS_10_0)) { 68 | %init(iOS10Up); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Source/PreferenceBundle/LaunchInSafeModeRootListController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Source/PreferenceBundle/LaunchInSafeModeRootListController.h 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LaunchInSafeModeRootListController : PSListController 12 | @end 13 | -------------------------------------------------------------------------------- /Source/PreferenceBundle/LaunchInSafeModeRootListController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Source/PreferenceBundle/LaunchInSafeModeRootListController.m 3 | // LaunchInSafeMode 4 | // 5 | // Created by inoahdev on 5/20/17. 6 | // Copyright © 2017 - 2018 inoahdev. All rights reserved. 7 | // 8 | 9 | #import "LaunchInSafeModeRootListController.h" 10 | 11 | @implementation LaunchInSafeModeRootListController 12 | - (NSArray *)specifiers { 13 | if (!_specifiers) { 14 | _specifiers = [[self loadSpecifiersFromPlistName:@"LaunchInSafeMode" target:self] retain]; 15 | } 16 | 17 | return _specifiers; 18 | } 19 | 20 | - (void)openURL:(NSURL *)url { 21 | #pragma clang diagnostic push 22 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 23 | 24 | UIApplication *application = [UIApplication sharedApplication]; 25 | if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) { 26 | [application openURL:url options:@{} completionHandler:nil]; 27 | } else { 28 | [application openURL:url]; 29 | } 30 | 31 | #pragma clang diagnostic pop 32 | } 33 | 34 | - (void)twitter { 35 | @autoreleasepool { 36 | UIApplication *application = [UIApplication sharedApplication]; 37 | if ([application canOpenURL:[NSURL URLWithString:@"tweetbot:"]]) { 38 | [self openURL:[NSURL URLWithString:@"tweetbot:///user_profile/inoahdev"]]; 39 | } else if ([application canOpenURL:[NSURL URLWithString:@"twitterrific:"]]) { 40 | [self openURL:[NSURL URLWithString:@"twitterrific://user?screen_name=inoahdev"]]; 41 | } else if ([application canOpenURL:[NSURL URLWithString:@"twitter:"]]) { 42 | [self openURL:[NSURL URLWithString:@"twitter://user?screen_name=inoahdev"]]; 43 | } else { 44 | [self openURL:[NSURL URLWithString:@"https://twitter.com/inoahdev"]]; 45 | } 46 | } 47 | } 48 | 49 | - (void)github { 50 | @autoreleasepool { 51 | [self openURL:[NSURL URLWithString:@"https://github.com/inoahdev/LaunchInSafeMode"]]; 52 | } 53 | } 54 | @end 55 | -------------------------------------------------------------------------------- /Source/PreferenceBundle/Makefile: -------------------------------------------------------------------------------- 1 | include $(THEOS)/makefiles/common.mk 2 | 3 | ARCHS = armv7 armv7s arm64 arm64e 4 | BUNDLE_NAME = LaunchInSafeMode 5 | 6 | LaunchInSafeMode_FILES = LaunchInSafeModeRootListController.m 7 | LaunchInSafeMode_INSTALL_PATH = /Library/PreferenceBundles 8 | LaunchInSafeMode_FRAMEWORKS = UIKit 9 | LaunchInSafeMode_PRIVATE_FRAMEWORKS = Preferences 10 | 11 | include $(THEOS_MAKE_PATH)/bundle.mk 12 | 13 | internal-stage:: 14 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) 15 | $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/LaunchInSafeMode.plist$(ECHO_END) 16 | -------------------------------------------------------------------------------- /Source/PreferenceBundle/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | LaunchInSafeMode 9 | CFBundleIdentifier 10 | com.inoahdev.launchinsafemode 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1.0 21 | NSPrincipalClass 22 | LaunchInSafeModeRootListController 23 | 24 | 25 | -------------------------------------------------------------------------------- /Source/PreferenceBundle/Resources/LaunchInSafeMode.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | cell 9 | PSSwitchCell 10 | default 11 | 12 | defaults 13 | com.inoahdev.launchinsafemode 14 | key 15 | kEnabled 16 | label 17 | Enable Tweak 18 | PostNotification 19 | iNoahDevLaunchInSafeModePreferencesChangedNotification 20 | 21 | 22 | cell 23 | PSGroupCell 24 | label 25 | 26 | 27 | 28 | cell 29 | PSButtonCell 30 | action 31 | github 32 | icon 33 | github@2x.png 34 | label 35 | Check out LaunchInSafeMode on GitHub 36 | 37 | 38 | cell 39 | PSButtonCell 40 | action 41 | twitter 42 | icon 43 | twitter@2x.png 44 | label 45 | Follow me on Twitter 46 | 47 | 48 | title 49 | LaunchInSafeMode 50 | 51 | 52 | -------------------------------------------------------------------------------- /Source/PreferenceBundle/Resources/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inoahdev/LaunchInSafeMode/39b4381d4a55516dd726ff7ebbb046585698d554/Source/PreferenceBundle/Resources/github.png -------------------------------------------------------------------------------- /Source/PreferenceBundle/Resources/github@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inoahdev/LaunchInSafeMode/39b4381d4a55516dd726ff7ebbb046585698d554/Source/PreferenceBundle/Resources/github@2x.png -------------------------------------------------------------------------------- /Source/PreferenceBundle/Resources/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inoahdev/LaunchInSafeMode/39b4381d4a55516dd726ff7ebbb046585698d554/Source/PreferenceBundle/Resources/twitter.png -------------------------------------------------------------------------------- /Source/PreferenceBundle/Resources/twitter@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inoahdev/LaunchInSafeMode/39b4381d4a55516dd726ff7ebbb046585698d554/Source/PreferenceBundle/Resources/twitter@2x.png -------------------------------------------------------------------------------- /Source/PreferenceBundle/entry.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | entry 6 | 7 | bundle 8 | LaunchInSafeMode 9 | cell 10 | PSLinkCell 11 | detail 12 | LaunchInSafeModeRootListController 13 | icon 14 | icon.png 15 | isController 16 | 17 | label 18 | LaunchInSafeMode 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.inoahdev.launchinsafemode 2 | Name: LaunchInSafeMode 3 | Depends: mobilesubstrate, preferenceloader 4 | Version: 1.0.5 5 | Architecture: iphoneos-arm 6 | Description: Use 3D Touch to selectively launch applications in a "safe mode" 7 | Maintainer: inoahdev 8 | Author: inoahdev 9 | Section: Tweaks 10 | --------------------------------------------------------------------------------