Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timonus/2cffc75500bbd04b66db673361026c12 to your computer and use it in GitHub Desktop.
Save timonus/2cffc75500bbd04b66db673361026c12 to your computer and use it in GitHub Desktop.
Workaround for SFSafariViewController preview + iOS 13 Context Menu negative interaction bug (FB7564018)
// Workaround for SFSafariViewController preview + iOS 13 context menu negative interaction bug (FB7564018)
// Examples: https://db.tt/hvBJOBdZwL, https://db.tt/egp20bSfS0
// With fix: https://db.tt/r5nCLNYbfs
@interface SFSafariViewController (ContextMenuBugWorkaround)
/// If this returns @c YES it's safe to present this view controller when "committing" from an iOS 13 context menu. If not, you should create a fresh @c SFSafariViewController and present that instead.
- (BOOL)canBePresentedOnContextMenuCompletion;
@end
@implementation SFSafariViewController (ContextMenuBugWorkaround)
- (BOOL)canBePresentedOnContextMenuCompletion
{
if (@available(iOS 13.2, *)) {
if (@available(iOS 14.0, *)) {
// This was fixed in iOS 14 beta 5.
} else {
// If there's an instance of "_SFURLTextPreviewView" in the hierarchy a preview's being shown https://db.tt/xie10gJe1p.
for (NSMutableArray<UIView *> *views = [NSMutableArray arrayWithObject:self.view]; views.count > 0; [views removeObjectAtIndex:0]) {
UIView *const view = views.firstObject;
if ([NSStringFromClass([view class]) containsString:@"PreviewView"]) {
return NO;
}
[views addObjectsFromArray:view.subviews];
}
}
}
// } else { /* Link preview collapsing didn't exist prior to iOS 13.2 */ }
return YES;
}
@end
@christianselig
Copy link

Thank you Tim!! Swift version for those who may be interested:

extension SFSafariViewController {
    var canBePresentedOnContextMenuCompletion: Bool {
        // Link preview collapsing wasn't available prior to iOS 13.2, so no possibility of bug
        guard #available(iOS 13.2, *) else { return true }
        
        var canPresentExistingViewController = true
        
        // If there's an instance of "_SFURLTextPreviewView" in the hierarchy a preview's being shown. https://db.tt/xie10gJe1p
        var views: [UIView] = [self.view]
        
        while let viewToInspect = views.first {
            let className = String(describing: type(of: viewToInspect))
            
            if className.contains("PreviewView") {
                canPresentExistingViewController = false
                break
            }
            
            views.append(contentsOf: viewToInspect.subviews)
            views.removeFirst()
        }
        
        return canPresentExistingViewController
    }
}

@timonus
Copy link
Author

timonus commented Aug 9, 2020

I just updated mine to early return like @christianselig's, should've been doing that before 😆

@christianselig
Copy link

Now yours is even cleaner. 😛

@timonus
Copy link
Author

timonus commented Aug 19, 2020

@christianselig heads up this appears to be fixed in iOS 14 beta 5 (updated the gist).

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