Skip to content

Instantly share code, notes, and snippets.

@JunyuKuang
Last active August 30, 2024 00:22
Show Gist options
  • Save JunyuKuang/75fcb81fd6046c0bf31933d85043d04b to your computer and use it in GitHub Desktop.
Save JunyuKuang/75fcb81fd6046c0bf31933d85043d04b to your computer and use it in GitHub Desktop.
Disable 77% scaling for Mac Catalyst apps. (Swift)
let overrideCatalystScaleFactor: Void = {
guard let sceneViewClass = NSClassFromString("UINSSceneView") as? NSObject.Type else {
return
}
if sceneViewClass.instancesRespond(to: NSSelectorFromString("scaleFactor")) {
// old
swizzleInstanceMethod(
class: sceneViewClass,
originalSelector: NSSelectorFromString("scaleFactor"),
swizzledSelector: #selector(swizzle_scaleFactor)
)
} else {
// macOS 11.3 Beta 3+
swizzleInstanceMethod(
class: sceneViewClass,
originalSelector: NSSelectorFromString("sceneToSceneViewScaleFactor"),
swizzledSelector: #selector(swizzle_scaleFactor)
)
swizzleInstanceMethod(
class: sceneViewClass,
originalSelector: NSSelectorFromString("fixedSceneToSceneViewScaleFactor"),
swizzledSelector: #selector(swizzle_scaleFactor2)
)
swizzleInstanceMethod(
class: NSClassFromString("UINSSceneContainerView"),
originalSelector: NSSelectorFromString("sceneToSceneViewScaleForLayout"),
swizzledSelector: #selector(swizzle_scaleFactor3)
)
}
}()
@objc private extension NSObject {
func swizzle_scaleFactor() -> CGFloat { 1 }
func swizzle_scaleFactor2() -> CGFloat { 1 }
func swizzle_scaleFactor3() -> CGFloat { 1 }
}
@JunyuKuang
Copy link
Author

For implementation of swizzleInstanceMethod, check Swizzle.swift

@Janneman84
Copy link

Janneman84 commented Sep 16, 2023

Thanks works well overall but I have an issue:

When picking a photo using UIImagePickerController or PHPickerViewController the touches/clicks are not registered correctly. It's probably best to have the picker stick to the default 77% scaling. Any tips on how to do this?

@JunyuKuang
Copy link
Author

@Janneman84 you could:
A. open those remote view controllers on a separated window scene, where scaling is set to 77% (requires modification on the swizzled methods);
or B. replace PHPickerViewController with a macOS equivalent such as UIDocumentPickerViewController or NSOpenPanel.

@Janneman84
Copy link

Thanks for the tip!

I figured out image pickers are pretty useless in MacOS anyway. A document picker works much better!

@wangwanjie
Copy link

tks, Can you please tell me where to place these code? I have tried in MacOS 14.5, but is doesn't work
`
#import "KGMacCatalystScaleDisabler.h"
#import <KGSafeKit/NSObject+KGSwizzle.h>

@implementation KGMacCatalystScaleDisabler
#if TARGET_OS_MACCATALYST

  • (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    Class sceneViewClass = NSClassFromString(@"UINSSceneView");
    if (sceneViewClass) {
    SEL originalSelector = NSSelectorFromString(@"scaleFactor");
    SEL swizzledSelector = @selector(swizzle_scaleFactor);

          if ([sceneViewClass instancesRespondToSelector:originalSelector]) {
              // Swizzle scaleFactor for older versions
              [sceneViewClass kg_swizzleInstanceMethod:originalSelector withMethod:swizzledSelector];
          } else {
              // Swizzle methods for macOS 11.3 Beta 3+
              originalSelector = NSSelectorFromString(@"sceneToSceneViewScaleFactor");
              [sceneViewClass kg_swizzleInstanceMethod:originalSelector withMethod:swizzledSelector];
    
              originalSelector = NSSelectorFromString(@"fixedSceneToSceneViewScaleFactor");
              SEL swizzledSelector2 = @selector(swizzle_scaleFactor2);
              [sceneViewClass kg_swizzleInstanceMethod:originalSelector withMethod:swizzledSelector2];
    
              Class sceneContainerViewClass = NSClassFromString(@"UINSSceneContainerView");
              if (sceneContainerViewClass) {
                  originalSelector = NSSelectorFromString(@"sceneToSceneViewScaleForLayout");
                  SEL swizzledSelector3 = @selector(swizzle_scaleFactor3);
                  [sceneContainerViewClass kg_swizzleInstanceMethod:originalSelector withMethod:swizzledSelector3];
              }
          }
      }
    

    });
    }

  • (CGFloat)swizzle_scaleFactor {
    return 1.0;
    }

  • (CGFloat)swizzle_scaleFactor2 {
    return 1.0;
    }

  • (CGFloat)swizzle_scaleFactor3 {
    return 1.0;
    }
    #endif
    @EnD

`

@JunyuKuang
Copy link
Author

I run the code in my AppDelegate.init()

@wangwanjie
Copy link

I run the code in my AppDelegate.init()

Thanks, I used your code instead of the OC code I wrote according to your logic, and it works now. I have another question, how did you find these methods to hook? I am considering whether to use this solution, because the API may change when the system is updated, and I don't know if there is any risk of audit for hooking this?

@beeradmoore
Copy link

Is any of this considered using a private API and risk rejectoin from the App Store?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment