WKWebView 在安全区域的横向内容宽度不正确

WKWebView incorrect content width in landscape with safe area

这是它的样子: 最简单的重现代码:

#import "ViewController.h"
#import <WebKit/WebKit.h>

@implementation ViewController

- (void)loadView
{
    WKWebView* webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:[[WKWebViewConfiguration alloc] init]];
    self.view = webView;

    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://apple.com"]]];
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

@end

这只会发生在设置了 viewport-fit=cover 的网站上。如果你在 Safari 中打开相同的网站,你可以看到第一个绘制框架有同样的问题,但它立即正确调整大小。

只有在横向启动时才会发生这种情况。 旋转到纵向并返回到横向解决了这个问题。即使最小化应用程序并再次打开它也能解决这个问题。

那么我可以通过代码做些什么来强制它自行修复吗? 我已经尝试调用 setNeedsLayoutlayoutIfNeeded 到整个 WKWebView 树。设置 scroller insets 将使内容看起来像没有设置 viewport-fit=cover。 这发生在 iOS 12 和 13(已测试)和 iOS 13 模拟器上。

您好,您需要更改视口。

请使用以下代码更改您的 "loadView" 函数。

- (void)loadView
{
    NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";

    WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
    WKUserContentController *wkUController = [[WKUserContentController alloc] init];
    [wkUController addUserScript:wkUScript];

    WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
    wkWebConfig.userContentController = wkUController;

    WKWebView* webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:wkWebConfig];
    webView.insetsLayoutMarginsFromSafeArea = false;
    webView.scrollView.insetsLayoutMarginsFromSafeArea = false;
    webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    webView.translatesAutoresizingMaskIntoConstraints = NO;
    self.view = webView;

    UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
    CGFloat topPadding = window.safeAreaInsets.top;
    CGFloat bottomPadding = window.safeAreaInsets.bottom;
    CGFloat leftPadding = window.safeAreaInsets.left;
    CGFloat rightPadding = window.safeAreaInsets.right;
    self.additionalSafeAreaInsets =  UIEdgeInsetsMake(-topPadding, -leftPadding, -bottomPadding, -rightPadding);
    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://apple.com"]]];
}

这不是完美的解决方案,但我设法通过将 webView 作为子视图添加到 self.view 并向 superview 而不是 safeArea 添加约束来获得相同的效果来解决这个问题。

解决方案:

  • 将尾随约束连接到变量
  • 设置约束已启用 false in viewDidLoad(优化设备方向检查)
  • 在函数 webView(WKWebView, didFinish: WKNavigation) 中将约束 isEnabled 设置为 true
  • 不要忘记注册到 webView 的 navigationDelegate

    @IBOutlet var mainWebView: WKWebView!
    @IBOutlet var trailingConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        let orientation = UIDevice.current.orientation
        if orientation == .landscapeLeft || orientation == .landscapeRight {
            trailingConstraint.isActive = false
        }
    
        mainWebView.navigationDelegate = self
        mainWebView.load(URLRequest(url: URL(string: "https://apple.com")!))
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        trailingConstraint.isActive = true
    }