Skip to content

Commit

Permalink
Support Xcode 16 format (v4)
Browse files Browse the repository at this point in the history
Framework now requires Xcode 16, but view hierarchies can be dumped for old iOS versions.
  • Loading branch information
LeoNatan committed Nov 21, 2024
1 parent 367e15c commit c193f07
Show file tree
Hide file tree
Showing 5 changed files with 349 additions and 171 deletions.
2 changes: 1 addition & 1 deletion LNViewHierarchyDumper/LNViewHierarchyDumper/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.3.1</string>
<string>1.4.-1</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,79 +7,106 @@

#import "LNViewHierarchyDumper+LibraryDebug.h"

//#if DEBUG
//@import ObjectiveC;
//@import Darwin;
//@import MachO.dyld;
//#endif
#define DEBUG_FRAMEWORKLOAD 0
#define DEBUG_REQUESTS 0
#define DEBUG_REQUESTS_REMOVE_COMPRESSION 1

#if DEBUG_FRAMEWORKLOAD || DEBUG_REQUESTS

#if DEBUG
@import ObjectiveC;
@import Darwin;
@import MachO.dyld;
#endif

@implementation LNViewHierarchyDumper (LibraryDebug)

//#if DEBUG
//static void func(const struct mach_header* mh, intptr_t vmaddr_slide)
//{
// Dl_info DlInfo;
// dladdr(mh, &DlInfo);
// const char* image_name = DlInfo.dli_fname;
//
// NSLog(@"%s", image_name);
//}
//
//
//static NSUInteger requestCounter = 0;
//static NSUInteger responseCounter = 0;
//
//__attribute__((constructor))
//static void zzz(void)
//{
// //We are looking for:
// // DebugHierarchyFoundation.framework
// // libViewDebuggerSupport.dylib
// _dyld_register_func_for_add_image(func);
//
// //The following code will dump requests made by Xcode View Hierarchy Inspector (and this framework) to ~/Desktop/Request_x.json
// {
// Class cls = NSClassFromString(@"DebugHierarchyRequest");
// SEL sel = NSSelectorFromString(@"requestWithBase64Data:error:");
// Method m = class_getClassMethod(cls, sel);
// id(*orig)(id, SEL, NSString*, NSError**) = (void*)method_getImplementation(m);
//
// method_setImplementation(m, imp_implementationWithBlock(^(id _self, NSString* request, NSError** error) {
// NSData* b64Data = [[NSData alloc] initWithBase64EncodedString:request options:0];
// NSString* homePath = NSHomeDirectory();
//#if TARGET_OS_SIMULATOR
// homePath = [homePath substringToIndex:[homePath rangeOfString:@"/Library"].location];
//#endif
// NSLog(@"%@", homePath);
// NSURL* outputURL = [[NSURL fileURLWithPath:homePath] URLByAppendingPathComponent:[NSString stringWithFormat:@"Desktop/Request_%@.json", @(requestCounter++)]];
// [b64Data writeToURL:outputURL atomically:YES];
//
// return orig(_self, sel, request, error);
// }));
// }
//
// {
// Class cls = NSClassFromString(@"DebugHierarchyTargetHub");
// SEL sel = NSSelectorFromString(@"performRequest:error:");
// Method m = class_getInstanceMethod(cls, sel);
// NSData*(*orig)(id, SEL, id, NSError**) = (void*)method_getImplementation(m);
// method_setImplementation(m, imp_implementationWithBlock(^(id _self, id request, NSError** error) {
// NSData* rv = orig(_self, sel, request, error);
//
// if(rv != nil)
// {
// NSString* homePath = NSHomeDirectory();
//#if TARGET_OS_SIMULATOR
// homePath = [homePath substringToIndex:[homePath rangeOfString:@"/Library"].location];
//#endif
// NSURL* outputURL = [[NSURL fileURLWithPath:homePath] URLByAppendingPathComponent:[NSString stringWithFormat:@"Desktop/Response_%@.json", @(responseCounter++)]];
// [rv writeToURL:outputURL atomically:YES];
// }
//
// return rv;
// }));
// }
//}
//#endif
#if DEBUG
#if DEBUG_FRAMEWORKLOAD
static void func(const struct mach_header* mh, intptr_t vmaddr_slide)
{
Dl_info DlInfo;
dladdr(mh, &DlInfo);
const char* image_name = DlInfo.dli_fname;

NSLog(@"%s", image_name);
}
#endif

#if DEBUG_REQUESTS
static NSUInteger requestCounter = 0;
static NSUInteger responseCounter = 0;
#endif

__attribute__((constructor))
static void zzz(void)
{
#if DEBUG_FRAMEWORKLOAD
//We are looking for:
// DebugHierarchyFoundation.framework
// libViewDebuggerSupport.dylib
_dyld_register_func_for_add_image(func);
#endif

#if DEBUG_REQUESTS
//The following code will dump requests made by Xcode View Hierarchy Inspector (and this framework) to ~/Desktop/Request_x.json
{
Class cls = NSClassFromString(@"DebugHierarchyRequest");
SEL sel = NSSelectorFromString(@"requestWithBase64Data:error:");
Method m = class_getClassMethod(cls, sel);
id(*orig)(id, SEL, NSString*, NSError**) = (void*)method_getImplementation(m);

method_setImplementation(m, imp_implementationWithBlock(^(id _self, NSString* request, NSError** error) {
NSData* b64Data = [[NSData alloc] initWithBase64EncodedString:request options:0];

#if DEBUG_REQUESTS_REMOVE_COMPRESSION
NSMutableDictionary* r = [NSJSONSerialization JSONObjectWithData:b64Data options:NSJSONReadingMutableContainers error:NULL];
r[@"DBGHierarchyRequestTransportCompression"] = @NO;
NSLog(@"%@", r);
b64Data = [NSJSONSerialization dataWithJSONObject:r options:0 error:NULL];
request = [b64Data base64EncodedStringWithOptions:0];
#endif

NSString* homePath = NSHomeDirectory();
#if TARGET_OS_SIMULATOR
homePath = [homePath substringToIndex:[homePath rangeOfString:@"/Library"].location];
#endif
NSURL* outputURL = [[NSURL fileURLWithPath:homePath] URLByAppendingPathComponent:[NSString stringWithFormat:@"Desktop/Request_%@.json", @(requestCounter++)]];

// NSLog(@"%@", outputURL.path);
// NSLog(@"%@", NSThread.callStackSymbols);

[b64Data writeToURL:outputURL atomically:YES];

return orig(_self, sel, request, error);
}));
}

{
Class cls = NSClassFromString(@"DebugHierarchyTargetHub");
SEL sel = NSSelectorFromString(@"performRequest:error:");
Method m = class_getInstanceMethod(cls, sel);
NSData*(*orig)(id, SEL, id, NSError**) = (void*)method_getImplementation(m);
method_setImplementation(m, imp_implementationWithBlock(^(id _self, id request, NSError** error) {
NSData* rv = orig(_self, sel, request, error);

if(rv != nil)
{
NSString* homePath = NSHomeDirectory();
#if TARGET_OS_SIMULATOR
homePath = [homePath substringToIndex:[homePath rangeOfString:@"/Library"].location];
#endif
NSURL* outputURL = [[NSURL fileURLWithPath:homePath] URLByAppendingPathComponent:[NSString stringWithFormat:@"Desktop/Response_%@.json", @(responseCounter++)]];
[rv writeToURL:outputURL atomically:YES];
}

return rv;
}));
}
#endif
}
#endif

@end

#endif
Loading

0 comments on commit c193f07

Please sign in to comment.