Forum Archive

UI Debugging Overlay in iOS13

qunwang6
# Pythonista script to show the UI Debugging overlay (private API) described in this blog post:
# http://ryanipete.com/blog/ios/swift/objective-c/uidebugginginformationoverlay/

from objc_util import ObjCClass, on_main_thread
UIDebuggingInformationOverlay = ObjCClass('UIDebuggingInformationOverlay')

@on_main_thread
def toggle_overlay():
  UIDebuggingInformationOverlay.prepareDebuggingOverlay()
  UIDebuggingInformationOverlay.overlay().toggleVisibility()

toggle_overlay()
#import <objc/runtime.h>

@interface DebuggingOverlay: NSObject

@end

@implementation DebuggingOverlay

+ (void)toggleOverlay {
    id debugInfoClass = NSClassFromString(@"UIDebuggingInformationOverlay");

    // In iOS 11, Apple added additional checks to disable this overlay unless the
    // device is an internal device. To get around this, we swizzle out the
    // -[UIDebuggingInformationOverlay init] method (which returns nil now if
    // the device is non-internal), and we call:
    // [[UIDebuggingInformationOverlayInvokeGestureHandler mainHandler] _handleActivationGesture:(UIGestureRecognizer *)]
    // to show the window, since that now adds the debugging view controllers, and calls
    // [overlay toggleVisibility] for us.
    if (@available(iOS 11.0, *)) {
        id handlerClass = NSClassFromString(@"UIDebuggingInformationOverlayInvokeGestureHandler");

        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            // Swizzle init of debugInfo class to just call [UIWindow init]
            Method initMethod = class_getInstanceMethod(debugInfoClass, @selector(init));
            IMP newInit = method_getImplementation(class_getInstanceMethod([UIWindow class], @selector(init)));
            method_setImplementation(initMethod, newInit);
        });

        id debugOverlayInstance = [debugInfoClass performSelector:NSSelectorFromString(@"overlay")];
        [debugOverlayInstance setFrame:[[UIScreen mainScreen] bounds]];

        UIGestureRecognizer *dummyGestureRecognizer = [[UIGestureRecognizer alloc] init];
        dummyGestureRecognizer.state = UIGestureRecognizerStateEnded;

        id handler = [handlerClass performSelector:NSSelectorFromString(@"mainHandler")];
        [handler performSelector:NSSelectorFromString(@"_handleActivationGesture:") withObject:dummyGestureRecognizer];
    } else {
        id debugOverlayInstance = [debugInfoClass performSelector:NSSelectorFromString(@"overlay")];
        [debugOverlayInstance performSelector:NSSelectorFromString(@"toggleVisibility")];
    }

}

@end

How to work in iOS13 ?

mikael

@qunwang6, very interesting, had not heard about the whole overlay. Not something I might personally need, but still.

Do we know why Apple has made it (almost) inaccessible?

I am sure swizzling experts like @JonB or @cvp could turn this into objc_util code in no time, although both have seemed to be a bit busy elsewhere lately.

cvp

@mikael said:

swizzling experts like JonB or cvp

Sincerely, I'm not an expert of swizzle, I only have used @JonB ´s code...

mikael

@cvp, that’s 100% more expertise than what I have. :-) (Please don’t check my math.)

qunwang6

@mikael its a private api and Apple don't like we used it.

JonB

Omz had a video of it a while back -- a few really useful bits, like ability to see entire view heirarchy, highlighting the selected element and such. My viewbrowser was intended to duplicate it, to some degree.