Skip to content

Commit f083733

Browse files
authored
Merge pull request #60 from jslegendre/fix-menubuilder-swizzle2
Fix PlayTools not loading for some apps in #57
2 parents 9d58e34 + a4cb88d commit f083733

File tree

2 files changed

+49
-30
lines changed

2 files changed

+49
-30
lines changed

PlayTools/Controls/PTFakeTouch/NSObject+Swizzle.m

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
#import <PlayTools/PlayTools-Swift.h>
1313
#import "PTFakeMetaTouch.h"
1414

15+
__attribute__((visibility("hidden")))
16+
@interface PTSwizzleLoader : NSObject
17+
@end
18+
1519
@implementation NSObject (Swizzle)
1620

1721
- (void) swizzleInstanceMethod:(SEL)origSelector withMethod:(SEL)newSelector
@@ -45,20 +49,6 @@ - (void) swizzleInstanceMethod:(SEL)origSelector withMethod:(SEL)newSelector
4549
}
4650
}
4751

48-
+ (void) load
49-
{
50-
// TODO: UINSview
51-
52-
if ([[PlaySettings shared] adaptiveDisplay]) {
53-
[objc_getClass("FBSSceneSettings") swizzleInstanceMethod:@selector(frame) withMethod:@selector(hook_frame)];
54-
[objc_getClass("FBSSceneSettings") swizzleInstanceMethod:@selector(bounds) withMethod:@selector(hook_bounds)];
55-
[objc_getClass("FBSDisplayMode") swizzleInstanceMethod:@selector(size) withMethod:@selector(hook_size)];
56-
}
57-
58-
[objc_getClass("IOSViewController") swizzleInstanceMethod:@selector(prefersPointerLocked) withMethod:@selector(hook_prefersPointerLocked)];
59-
[self swizzleInstanceMethod:@selector(init) withMethod:@selector(hook_init)];
60-
}
61-
6252
- (BOOL) hook_prefersPointerLocked {
6353
return false;
6454
}
@@ -76,15 +66,51 @@ - (CGSize) hook_size {
7666
}
7767

7868
bool menuWasCreated = false;
79-
80-
-(id) hook_init {
69+
- (id) initWithRootMenuHook:(id)rootMenu {
70+
self = [self initWithRootMenuHook:rootMenu];
8171
if (!menuWasCreated) {
82-
if ([[self class] isEqual: NSClassFromString(@"_UIMenuBuilder")]) {
83-
[PlayCover initMenuWithMenu: self];
84-
menuWasCreated = TRUE;
85-
}
72+
[PlayCover initMenuWithMenu: self];
73+
menuWasCreated = TRUE;
8674
}
87-
8875
return self;
8976
}
77+
78+
@end
79+
80+
/*
81+
This class only exists to apply swizzles from the +load of a class that won't have any categories/extensions. The reason
82+
for not doing this in a C module initializer is that obj-c initialization happens before any __attribute__((constructor))
83+
is called. This way we can guarantee the hooks will be applied before [PlayCover launch] is called (in PlayLoader.m).
84+
85+
Side note:
86+
While adding method replacements to NSObject does work, I'm not certain this doesn't (or won't) have any side effects. The
87+
way Apple does method swizzling internally is by creating a category of the swizzled class and adding the replacements there.
88+
This keeps all those replacements "local" to that class. Example:
89+
90+
'''
91+
@interface FBSSceneSettings (Swizzle)
92+
-(CGRect) hook_frame {
93+
...
94+
}
95+
@end
96+
97+
Somewhere else:
98+
swizzle(FBSSceneSettings.class, @selector(frame), @selector(hook_frame);
99+
'''
100+
101+
However, doing this would require generating @interface declarations (either with class-dump or by hand) which would add a lot
102+
of code and complexity. I'm not sure this trade-off is "worth it", at least at the time of writing.
103+
*/
104+
@implementation PTSwizzleLoader
105+
+ (void)load {
106+
if ([[PlaySettings shared] adaptiveDisplay]) {
107+
[objc_getClass("FBSSceneSettings") swizzleInstanceMethod:@selector(frame) withMethod:@selector(hook_frame)];
108+
[objc_getClass("FBSSceneSettings") swizzleInstanceMethod:@selector(bounds) withMethod:@selector(hook_bounds)];
109+
[objc_getClass("FBSDisplayMode") swizzleInstanceMethod:@selector(size) withMethod:@selector(hook_size)];
110+
}
111+
112+
[objc_getClass("_UIMenuBuilder") swizzleInstanceMethod:sel_getUid("initWithRootMenu:") withMethod:@selector(initWithRootMenuHook:)];
113+
[objc_getClass("IOSViewController") swizzleInstanceMethod:@selector(prefersPointerLocked) withMethod:@selector(hook_prefersPointerLocked)];
114+
}
115+
90116
@end

PlayTools/PlayCover.swift

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,8 @@ public class PlayCover: NSObject {
1919
}
2020

2121
@objc static public func initMenu(menu: NSObject) {
22-
delay(0.005) {
23-
guard let menuBuilder = menu as? UIMenuBuilder else { return }
24-
25-
shared.menuController = MenuController(with: menuBuilder)
26-
delay(0.005) {
27-
UIMenuSystem.main.setNeedsRebuild()
28-
UIMenuSystem.main.setNeedsRevalidate()
29-
}
30-
}
22+
guard let menuBuilder = menu as? UIMenuBuilder else { return }
23+
shared.menuController = MenuController(with: menuBuilder)
3124
}
3225

3326
static public func quitWhenClose() {

0 commit comments

Comments
 (0)