Skip to content

Instantly share code, notes, and snippets.

@JunyuKuang
Last active September 29, 2024 00:58
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?

@JunyuKuang
Copy link
Author

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

Running fine for years. Apple don't cares.

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