├── .gitignore ├── Makefile ├── README.md ├── ShortcutToDebug.plist ├── SpringBoard.h ├── Tap2DebugRootless.png ├── TapSB.x ├── Tweak.x ├── common.h ├── control ├── resource ├── Dopamine2.0.8.ipa └── Filza.ipa └── xia0.h /.gitignore: -------------------------------------------------------------------------------- 1 | .theos/ 2 | packages/ 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GO_EASY_ON_ME = 1 2 | THEOS_DEVICE_IP = localhost -o StrictHostKeyChecking=no 3 | THEOS_DEVICE_PORT = 2222 4 | ARCHS = arm64 arm64e 5 | TARGET := iphone:clang:latest:15.0 6 | 7 | THEOS_PACKAGE_SCHEME=rootless 8 | THEOS_PACKAGE_INSTALL_PREFIX=/var/jb 9 | 10 | INSTALL_TARGET_PROCESSES = SpringBoard 11 | 12 | include $(THEOS)/makefiles/common.mk 13 | 14 | TWEAK_NAME = ShortcutToDebug 15 | 16 | ShortcutToDebug_FILES = Tweak.x TapSB.x 17 | ShortcutToDebug_CFLAGS = -fobjc-arc 18 | 19 | include $(THEOS_MAKE_PATH)/tweak.mk 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tap2DebugRootless 2 | 基于 Dopamine 无根越狱实现的插件,该插件可以通过使用 3D Touch 快速 Debug 调试某个 App 3 | 4 | #### Screenshots 5 | 6 | 7 | 8 | #### Install 9 | 10 | ##### 准备: 11 | 12 | - 安装巨魔 (https://ios.cfw.guide/installing-trollstore/) 13 | - 通过巨魔安装`resource`里的`Dopamine2.0.8`并执行越狱操作 14 | 15 | - 通过巨魔安装`resource`里的`Filza` 16 | - 安装`Theos`环境 (参考文章`https://cloud.tencent.com/developer/article/2007333`) 17 | 18 | ##### 方式一:自主编译 19 | 20 | - ```shell 21 | https://github.com/DargonLee/Tap2DebugRootless.git 22 | ``` 23 | 24 | - ``` 25 | cd Tap2DebugRootless 26 | ``` 27 | 28 | - ```shell 29 | make clean && make && make package 30 | ``` 31 | 32 | - 拷贝`packages`文件夹下的`deb`文件到`Filza`的某个目录,然后点击安装 33 | 34 | - 安装成功后打开`Dopamine`重启用户空间就可以正常使用了 35 | 36 | ##### 方式二:直接安装 37 | 38 | - 下载Release包 39 | - 拷贝`deb`文件到`Filza`的某个目录,然后点击安装 40 | - 安装成功后打开`Dopamine`重启用户空间就可以正常使用了 41 | 42 | #### Usage 43 | 44 | - 长按要调试的 App 选择`Tap2Debug` 45 | 46 | - 点击`Attach` 47 | 48 | - 然后点击打开 App 49 | 50 | - 在 Mac 设备上打开终端输入`lldb` 51 | 52 | - ```shell 53 | (lldb) process connect connect://192.168.12.76:20221 54 | ``` 55 | 56 | - 192.168.12.76 是你手机的 ip 地址 57 | 58 | #### Credit 59 | 60 | - [4ch12dy/Tap2Debug: tap shortcut(double tap app icon is deault close because app will pause) to debug app (support iOS11/12/13 and A12) (github.com)](https://github.com/4ch12dy/Tap2Debug) 61 | - [SpringBoard tweak 双击图标启动debugserver - 干货分享 - 睿论坛 (iosre.com)](https://iosre.com/t/springboard-tweak-双击图标启动debugserver/16420) 62 | -------------------------------------------------------------------------------- /ShortcutToDebug.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | -------------------------------------------------------------------------------- /SpringBoard.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RBSProcessIdentity : NSObject 4 | @property(readonly, copy, nonatomic) NSString *executablePath; 5 | @property(readonly, copy, nonatomic) NSString *embeddedApplicationIdentifier; 6 | @end 7 | 8 | @interface FBProcessExecutionContext : NSObject 9 | @property (nonatomic,copy) NSDictionary* environment; 10 | @property (nonatomic,copy) RBSProcessIdentity* identity; 11 | @end 12 | 13 | @interface FBProcessManager : NSObject 14 | - (void)handleSafeModeForExecutionContext:(FBProcessExecutionContext*)executionContext withApplicationID:(NSString*)applicationID; 15 | @end 16 | 17 | 18 | 19 | @interface SBApplicationInfo : NSObject 20 | @property (nonatomic,readonly) NSURL* executableURL; 21 | @property (nonatomic,readonly) BOOL hasHiddenTag; 22 | @property (nonatomic,retain,readonly) NSArray* tags; 23 | @end 24 | 25 | @interface SBApplication : NSObject 26 | - (SBApplicationInfo*)_appInfo; 27 | @end 28 | 29 | @interface SBSApplicationShortcutIcon : NSObject 30 | @end 31 | 32 | @interface SBSApplicationShortcutSystemItem : SBSApplicationShortcutIcon 33 | - (instancetype)initWithSystemImageName:(NSString*)systemImageName; 34 | @end 35 | 36 | @interface SBSApplicationShortcutItem : NSObject 37 | @property (nonatomic,copy) NSString* type; 38 | @property (nonatomic,copy) NSString* localizedTitle; 39 | @property (nonatomic,copy) NSString* localizedSubtitle; 40 | @property (nonatomic,copy) SBSApplicationShortcutIcon* icon; 41 | @property (nonatomic,copy) NSDictionary* userInfo; 42 | @property (assign,nonatomic) NSUInteger activationMode; 43 | @property (nonatomic,copy) NSString* bundleIdentifierToLaunch; 44 | @end 45 | 46 | @interface SBIconView : NSObject 47 | - (NSString*)applicationBundleIdentifier; 48 | - (NSString*)applicationBundleIdentifierForShortcuts; 49 | @end 50 | 51 | @interface SBUIAppIconForceTouchControllerDataProvider : NSObject 52 | - (NSString*)applicationBundleIdentifier; 53 | @end 54 | 55 | @interface SBIconController : NSObject 56 | @property (weak, nonatomic) id _rootFolderController; 57 | @end 58 | 59 | @interface SBUIAppIconForceTouchController : NSObject 60 | @property (weak, nonatomic) SBIconController* delegate; 61 | - (void) dismissAnimated:(BOOL)arg1 withCompletionHandler:(void (^)())block; 62 | @end -------------------------------------------------------------------------------- /Tap2DebugRootless.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DargonLee/Tap2DebugRootless/9f1cead507f0adc39f5f96ba41891863001e7864/Tap2DebugRootless.png -------------------------------------------------------------------------------- /TapSB.x: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "SpringBoard.h" 4 | #import "xia0.h" 5 | #import "common.h" 6 | 7 | 8 | NSString* toggleOneTimeApplicationID; 9 | #ifndef kCFCoreFoundationVersionNumber_iOS_11_0 10 | #define kCFCoreFoundationVersionNumber_iOS_11_0 1443.00 11 | #endif 12 | 13 | #ifndef kCFCoreFoundationVersionNumber_iOS_13_0 14 | #define kCFCoreFoundationVersionNumber_iOS_13_0 1665.15 15 | #endif 16 | 17 | %group iOS10Down 18 | %hook SBApplication 19 | 20 | - (id)valueForKeyPath:(NSString*)keyPath 21 | { 22 | if([keyPath isEqualToString:@"info.xia0_hasHiddenTag"]) 23 | { 24 | return [[self _appInfo] valueForKey:@"xia0_hasHiddenTag"]; 25 | } 26 | 27 | return %orig; 28 | } 29 | 30 | %end 31 | %end 32 | 33 | %group Shortcut_iOS13Up 34 | 35 | %hook SBIconView 36 | 37 | - (NSArray *)applicationShortcutItems 38 | { 39 | NSArray* orig = %orig; 40 | 41 | NSString* applicationID; 42 | if([self respondsToSelector:@selector(applicationBundleIdentifier)]) 43 | { 44 | applicationID = [self applicationBundleIdentifier]; 45 | } 46 | else if([self respondsToSelector:@selector(applicationBundleIdentifierForShortcuts)]) 47 | { 48 | applicationID = [self applicationBundleIdentifierForShortcuts]; 49 | } 50 | 51 | if(!applicationID) 52 | { 53 | return orig; 54 | } 55 | 56 | 57 | SBSApplicationShortcutItem* toggleSafeModeOnceItem = [[%c(SBSApplicationShortcutItem) alloc] init]; 58 | 59 | toggleSafeModeOnceItem.localizedTitle = @"Tap2Debug"; 60 | 61 | 62 | //toggleSafeModeOnceItem.icon = [[%c(SBSApplicationShortcutSystemItem) alloc] initWithSystemImageName:@"fx"]; 63 | toggleSafeModeOnceItem.bundleIdentifierToLaunch = applicationID; 64 | toggleSafeModeOnceItem.type = @"com.xia0.tap2debug"; 65 | 66 | return [orig arrayByAddingObject:toggleSafeModeOnceItem]; 67 | 68 | return orig; 69 | } 70 | 71 | + (void)activateShortcut:(SBSApplicationShortcutItem*)item withBundleIdentifier:(NSString*)bundleID forIconView:(id)iconView 72 | { 73 | if(![item.type isEqualToString:@"com.xia0.tap2debug"]){ 74 | return %orig; 75 | } 76 | 77 | XLOG("bundleID:%@ view:%@", bundleID, iconView); 78 | GCD_AFTER_MAIN(0.01) 79 | show_debug_view([iconView findViewController], bundleID); 80 | GCD_END 81 | } 82 | 83 | %end 84 | 85 | %end 86 | 87 | %group Shortcut_iOS12Down 88 | 89 | %hook SBUIAppIconForceTouchControllerDataProvider 90 | 91 | - (NSArray *)applicationShortcutItems 92 | { 93 | NSArray* orig = %orig; 94 | 95 | NSString* applicationID = [self applicationBundleIdentifier]; 96 | 97 | if(!applicationID) 98 | { 99 | return orig; 100 | } 101 | 102 | 103 | SBSApplicationShortcutItem* toggleSafeModeOnceItem = [[%c(SBSApplicationShortcutItem) alloc] init]; 104 | 105 | toggleSafeModeOnceItem.localizedTitle = @"ShortcutToDebug"; 106 | 107 | //toggleSafeModeOnceItem.icon = [[%c(SBSApplicationShortcutSystemItem) alloc] init]; 108 | toggleSafeModeOnceItem.bundleIdentifierToLaunch = applicationID; 109 | toggleSafeModeOnceItem.type = @"com.xia0.tap2debug"; 110 | 111 | if(!orig) 112 | { 113 | return @[toggleSafeModeOnceItem]; 114 | } 115 | else 116 | { 117 | return [orig arrayByAddingObject:toggleSafeModeOnceItem]; 118 | } 119 | 120 | return orig; 121 | } 122 | 123 | %end 124 | 125 | %hook SBUIAppIconForceTouchController 126 | 127 | - (void)appIconForceTouchShortcutViewController:(id)arg1 activateApplicationShortcutItem:(SBSApplicationShortcutItem*)item 128 | { 129 | if(![item.type isEqualToString:@"com.xia0.tap2debug"]){ 130 | return %orig; 131 | } 132 | 133 | NSString* bundleID = item.bundleIdentifierToLaunch; 134 | // Ivar ivar = object_getInstanceVariable(object_getClass(self.delegate), "_rootFolderController", NULL); 135 | // id rootFolderController = (__bridge id)((__bridge void *)self.delegate + ivar_getOffset(ivar)); 136 | // id rootFolderController = MSHookIvar(self.delegate, "_rootFolderController"); 137 | SBIconController* sbivc = self.delegate; 138 | id rootFolderController = sbivc._rootFolderController; 139 | XLOG(@"tap on app:%@ vc:%@ rootFolderController:%@", bundleID, arg1, rootFolderController); 140 | [self dismissAnimated:YES withCompletionHandler:^{ 141 | GCD_AFTER_MAIN(0.01) 142 | show_debug_view(rootFolderController, bundleID); 143 | GCD_END 144 | }]; 145 | } 146 | 147 | %end 148 | 149 | %end 150 | 151 | %ctor 152 | { 153 | %init(); 154 | if(kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_13_0) 155 | { 156 | // %init(SafeMode_iOS13Up); 157 | %init(Shortcut_iOS13Up); 158 | } 159 | else 160 | { 161 | // %init(SafeMode_iOS12Down); 162 | %init(Shortcut_iOS12Down); 163 | } 164 | 165 | if(kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_11_0) 166 | { 167 | %init(iOS10Down); 168 | } 169 | } -------------------------------------------------------------------------------- /Tweak.x: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import "xia0.h" 5 | #import "common.h" 6 | 7 | @interface NSTask : NSObject 8 | 9 | - (id)init; 10 | - (void)setLaunchPath:(NSString *)path; 11 | - (void)setArguments:(NSArray *)arguments; 12 | - (void)launch; 13 | - (int)processIdentifier; 14 | 15 | @end 16 | 17 | @interface LSApplicationProxy : NSObject 18 | + (id) applicationProxyForIdentifier:(id)arg1; 19 | @property (readonly, nonatomic) NSString* canonicalExecutablePath; 20 | @end 21 | 22 | @interface TaskManager : NSObject 23 | + (TaskManager*)sharedManager; 24 | @property (nonatomic,strong) NSTask * runningTask; 25 | @end 26 | 27 | @implementation TaskManager 28 | + (TaskManager*)sharedManager { 29 | static TaskManager *_sharedSingleton = nil; 30 | static dispatch_once_t onceToken; 31 | dispatch_once(&onceToken, ^{ 32 | _sharedSingleton = [[self alloc] init]; 33 | }); 34 | return _sharedSingleton; 35 | } 36 | @end 37 | 38 | @interface SBApplication : NSObject 39 | @property(copy, nonatomic) NSArray *dynamicShortcutItems; 40 | @property(copy, nonatomic) NSArray *staticShortcutItems; 41 | @property(copy, nonatomic) NSString* bundleIdentifier; 42 | - (id)badgeNumberOrString; 43 | - (void)loadStaticShortcutItemsFromInfoDictionary:(id)arg1 bundle:(id)arg2; 44 | - (NSString*)bundleIdentifier; 45 | - (NSString*)displayName; 46 | @end; 47 | 48 | @interface SBIcon : NSObject 49 | @property(copy, nonatomic) SBApplication* application; 50 | - (void)launchFromLocation:(int)location; 51 | - (BOOL)isFolderIcon; 52 | - (id)badgeNumberOrString; 53 | @end 54 | 55 | @interface SBIconView : UIView 56 | 57 | @property(nullable, nonatomic,copy) NSArray *gestureRecognizers; 58 | @property(nonatomic,copy) NSString *applicationBundleIdentifierForShortcuts; 59 | @property(nonatomic,copy) SBIcon *icon; 60 | @end 61 | 62 | void show_debug_process_view(UIViewController* showVC, NSString* _bundleid, NSString* _attachModel) { 63 | NSString* bundle = _bundleid; 64 | if(!bundle){ 65 | XLOG(@"error bundleid is null"); 66 | return; 67 | } 68 | UIViewController *vc = showVC; 69 | 70 | NSString *debugserver = @"/var/jb/bin/debugserver"; 71 | NSString *ip_port = @"0.0.0.0:1234"; 72 | NSString *last_server = [[NSUserDefaults standardUserDefaults] objectForKey:@"server_bin_path"] ; 73 | NSString *last_ip =[[NSUserDefaults standardUserDefaults] objectForKey:@"ip_port"] ; 74 | if(last_server!=nil){ 75 | debugserver = last_server; 76 | } 77 | if(last_ip != nil){ 78 | ip_port = last_ip; 79 | } 80 | 81 | Class LSApplicationProxy_class = objc_getClass("LSApplicationProxy"); 82 | NSObject *proxyObj = [LSApplicationProxy_class performSelector:@selector(applicationProxyForIdentifier:) withObject:bundle]; 83 | NSString *canonicalExecutablePath = [proxyObj performSelector:@selector(canonicalExecutablePath)]; 84 | 85 | UIAlertController *panel = [UIAlertController alertControllerWithTitle:@"🍎 SERVER LAUNCHER" message:canonicalExecutablePath preferredStyle:UIAlertControllerStyleAlert]; 86 | 87 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 88 | textField.userInteractionEnabled = NO; 89 | textField.placeholder = @"server path(not null)"; 90 | textField.text = debugserver; 91 | GCD_AFTER_MAIN(0.3) 92 | textField.userInteractionEnabled = YES; 93 | GCD_END 94 | }]; 95 | if ([_attachModel isEqualToString:@"Spawn"]) { 96 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 97 | textField.placeholder = @"-x auto"; 98 | textField.text = @"-x auto"; 99 | textField.enabled = NO; 100 | textField.textColor = [UIColor lightGrayColor]; 101 | }]; 102 | } 103 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 104 | textField.placeholder = @"ip:port(nullable)"; 105 | textField.text = ip_port; 106 | }]; 107 | if ([_attachModel isEqualToString:@"Attach"]) { 108 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 109 | textField.placeholder = @"-a"; 110 | textField.text = @"-a"; 111 | textField.enabled = NO; 112 | textField.textColor = [UIColor lightGrayColor]; 113 | }]; 114 | } 115 | 116 | [panel addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 117 | textField.placeholder = @"executable path(not null)"; 118 | if ([_attachModel isEqualToString:@"Spawn"]) { 119 | textField.text = canonicalExecutablePath; 120 | }else { 121 | textField.text = [canonicalExecutablePath lastPathComponent]; 122 | } 123 | 124 | textField.enabled = NO; 125 | textField.textColor = [UIColor lightGrayColor]; 126 | }]; 127 | 128 | UIAlertAction *okaction = [UIAlertAction actionWithTitle:@"▶ Start Server" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 129 | NSMutableArray *args = [NSMutableArray array]; 130 | 131 | UITextField *tf_server = panel.textFields[0]; 132 | 133 | UITextField *tf_ip = nil; 134 | UITextField *tf_a = nil; 135 | if ([_attachModel isEqualToString:@"Attach"]) { 136 | tf_ip = panel.textFields[1]; 137 | tf_a = panel.textFields[2]; 138 | }else { 139 | tf_ip = panel.textFields[2]; 140 | tf_a = panel.textFields[1]; 141 | } 142 | 143 | UITextField *tf_exepath = panel.textFields[3]; 144 | 145 | NSString *bin_serverpath = [tf_server.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 146 | if (!bin_serverpath || bin_serverpath.length == 0) { 147 | XLOG(@"server path is null,stop"); 148 | return ; 149 | } 150 | 151 | NSString *arg_ipport = [tf_ip.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 152 | if (!arg_ipport || arg_ipport.length == 0) { 153 | XLOG(@"ipport is null,continue"); 154 | return ; 155 | } 156 | 157 | if ([_attachModel isEqualToString:@"Attach"]) { 158 | [args addObject:arg_ipport]; 159 | [args addObject:@"-a"]; 160 | }else { 161 | [args addObject:@"-x"]; 162 | [args addObject:@"auto"]; 163 | [args addObject:arg_ipport]; 164 | } 165 | 166 | NSString *arg_exepath = [tf_exepath.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 167 | [args addObject:arg_exepath]; 168 | 169 | XLOG(@"launch path %@",bin_serverpath); 170 | XLOG(@"%@ %@ %@",bin_serverpath,arg_ipport,arg_exepath); 171 | XLOG(@"args: %@",args); 172 | 173 | [[NSUserDefaults standardUserDefaults] setObject:bin_serverpath forKey:@"server_bin_path"] ; 174 | [[NSUserDefaults standardUserDefaults] setObject:arg_ipport forKey:@"ip_port"] ; 175 | [[NSUserDefaults standardUserDefaults] synchronize]; 176 | 177 | NSTask * task = [TaskManager sharedManager].runningTask; 178 | if(task){ 179 | kill(task.processIdentifier,SIGKILL); 180 | task = nil; 181 | } 182 | task = [[NSTask alloc]init]; 183 | [task setLaunchPath:bin_serverpath]; 184 | [task setArguments:args]; 185 | [task launch]; 186 | [TaskManager sharedManager].runningTask = task; 187 | }]; 188 | UIAlertAction *cancelaction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 189 | XLOG(@"cancel"); 190 | }]; 191 | 192 | [panel addAction:okaction]; 193 | [panel addAction:cancelaction]; 194 | XLOG("vc:%@", vc); 195 | [vc presentViewController:panel animated:YES completion:nil]; 196 | } 197 | 198 | 199 | void show_debug_view(UIViewController* showVC, NSString* _bundleid){ 200 | UIAlertController *panel = [UIAlertController alertControllerWithTitle:@"Choose Attach Model" message:nil preferredStyle:UIAlertControllerStyleAlert]; 201 | 202 | UIAlertAction *attachaction = [UIAlertAction actionWithTitle:@"Attach" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 203 | XLOG(@"Attach Mode"); 204 | show_debug_process_view(showVC, _bundleid, @"Attach"); 205 | }]; 206 | UIAlertAction *spawnaction = [UIAlertAction actionWithTitle:@"Spawn" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 207 | XLOG(@"Spawn Mode"); 208 | show_debug_process_view(showVC, _bundleid, @"Spawn"); 209 | }]; 210 | 211 | UIAlertAction *stopction = [UIAlertAction actionWithTitle:@"🛑Stop" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 212 | XLOG(@"Spawn Mode"); 213 | NSTask *task = [TaskManager sharedManager].runningTask; 214 | kill(task.processIdentifier,SIGKILL); 215 | task = nil; 216 | }]; 217 | 218 | UIAlertAction *cancelaction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 219 | XLOG(@"cancel"); 220 | }]; 221 | 222 | [panel addAction:attachaction]; 223 | [panel addAction:spawnaction]; 224 | [panel addAction:cancelaction]; 225 | 226 | NSTask *task = [TaskManager sharedManager].runningTask; 227 | if(task){ 228 | [panel addAction:stopction]; 229 | } 230 | 231 | [showVC presentViewController:panel animated:YES completion:nil]; 232 | } 233 | 234 | %hook SBIconView 235 | 236 | %new 237 | -(void)handleDoubleClick:(UITapGestureRecognizer*)doubleTap 238 | { 239 | NSString* bid = self.icon.application.bundleIdentifier; 240 | XLOG(@"id:%@",bid); 241 | show_debug_view([self findViewController], bid); 242 | } 243 | %end 244 | 245 | 246 | %hook SBIconView 247 | 248 | - (void)didMoveToWindow 249 | { 250 | %orig; 251 | #if TROGGLE_WITH_DOUBLE_TAP 252 | UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleClick:)]; 253 | [doubleTap setNumberOfTapsRequired:2]; 254 | [self addGestureRecognizer:doubleTap]; 255 | NSArray * ges = self.gestureRecognizers; 256 | for(UITapGestureRecognizer * each in ges){ 257 | if([each isKindOfClass:[UITapGestureRecognizer class]]){ 258 | [each requireGestureRecognizerToFail: doubleTap]; 259 | } 260 | } 261 | #endif 262 | } 263 | 264 | - (void)tapGestureDidChange:(id)ges 265 | { 266 | XLOG(@"single click"); 267 | %orig; 268 | } 269 | 270 | %end 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | #define TROGGLE_WITH_DOUBLE_TAP 0 2 | 3 | @interface UIView(findvc) 4 | -(UIViewController*)findViewController; 5 | @end 6 | 7 | @implementation UIView(find) 8 | -(UIViewController*)findViewController 9 | { 10 | UIResponder* target= self; 11 | while (target) { 12 | target = target.nextResponder; 13 | if ([target isKindOfClass:[UIViewController class]]) { 14 | break; 15 | } 16 | } 17 | return (UIViewController*)target; 18 | } 19 | @end 20 | 21 | void show_debug_view(UIViewController* showVC, NSString* _bundleid); -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.harans.tweak.shortcuttodebug 2 | Name: Tap2DebugRootless 3 | Version: 0.1.0 4 | Architecture: iphoneos-arm 5 | Description: 无根越狱下通过 3D Touch 快捷方式打开设置中的“调试”页面 6 | Maintainer: Harlans 7 | Author: Harlans 8 | Section: Tweaks 9 | Depends: mobilesubstrate (>= 0.9.5000) 10 | -------------------------------------------------------------------------------- /resource/Dopamine2.0.8.ipa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DargonLee/Tap2DebugRootless/9f1cead507f0adc39f5f96ba41891863001e7864/resource/Dopamine2.0.8.ipa -------------------------------------------------------------------------------- /resource/Filza.ipa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DargonLee/Tap2DebugRootless/9f1cead507f0adc39f5f96ba41891863001e7864/resource/Filza.ipa -------------------------------------------------------------------------------- /xia0.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | // GCD 5 | #define GCD_RUN_MAIN dispatch_async(dispatch_get_main_queue(),^(){ 6 | #define GCD_RUN(__dp_q) dispatch_async(dispatch_queue_create(__dp_q, NULL),^(){ 7 | #define GCD_AFTER_MAIN(__dp_af) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(__dp_af * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 8 | #define GCD_AFTER(__dp_af, __dp_q) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(__dp_af * NSEC_PER_SEC)), dispatch_queue_create(__dp_q, NULL), ^{ 9 | #define GCD_END }); 10 | #define SLEEP(sec) [NSThread sleepForTimeInterval:sec] 11 | 12 | #define XLOG(log, ...) NSLog(@"[tap2debug] " log, ##__VA_ARGS__) 13 | 14 | #define X_OC_NEW_NAME(CLASS_ID, SEL_ID) _x_new_func$##CLASS_ID##$##SEL_ID 15 | #define X_OC_NEW(CLASS_ID, SEL_ID, ...) X_OC_NEW_NAME(CLASS_ID, SEL_ID)(id _id, SEL _sel, ##__VA_ARGS__) 16 | 17 | #define X_OC_ORI_NAME(CLASS_ID, SEL_ID) _x_orig_func$##CLASS_ID##$##SEL_ID 18 | #define X_OC_ORI(CLASS_ID, SEL_ID, ...) (*X_OC_ORI_NAME(CLASS_ID, SEL_ID))(id _id, SEL _sel, ##__VA_ARGS__) 19 | 20 | #define X_OC_HOOK(CLASS_ID, SEL_ID, CLASS_NAME, SEL_NAME) do{ Method _method_$##CLASS_ID##$##SEL_ID = class_getClassMethod(NSClassFromString(@""CLASS_NAME), NSSelectorFromString(@""SEL_NAME)); X_OC_ORI_NAME(CLASS_ID,SEL_ID) = (void*)method_getImplementation(_method_$##CLASS_ID##$##SEL_ID); method_setImplementation(_method_$##CLASS_ID##$##SEL_ID, (IMP)&X_OC_NEW_NAME(CLASS_ID, SEL_ID)); }while(0) 21 | 22 | 23 | #define X_C_NEW_NAME(FUNC_ADDR) _x_c_new_func_##FUNC_ADDR 24 | #define X_C_NEW(FUNC_ADDR, ...) X_C_NEW_NAME(FUNC_ADDR)(##__VA_ARGS__) 25 | 26 | #define X_C_ORI_NAME(FUNC_ADDR) _x_c_orig_func_##FUNC_ADDR 27 | #define X_C_ORI(FUNC_ADDR, ...) (*X_C_ORI_NAME(FUNC_ADDR))(##__VA_ARGS__) 28 | 29 | #define X_C_HOOK(FUNC_ADDR) do{ void* _sub_##FUNC_ADDR = (void*)(_dyld_get_image_vmaddr_slide(0) + FUNC_ADDR); MSHookFunction(_sub_##FUNC_ADDR, X_C_NEW_NAME(FUNC_ADDR), &X_C_ORI_NAME(FUNC_ADDR)); }while(0) 30 | 31 | --------------------------------------------------------------------------------