为从Nib或Storyboard生成的WKWebView设置自定义WKWebViewConfiguration

时间:2019-05-31 20:28:15

标签: iphone xcode storyboard wkwebview nib

我想为我的应用程序使用自定义URL方案,但是无法配置URL方案。

当我以编程方式创建WKWebView对象时(使用initWithFrame:...),我能够指定自己的WKWebViewConfiguration对象,但是当在Nib / Storyboard中自动创建WKWebView时(通过initWithCoder :),我无法指定组态。该配置为只读,因此事后我无法对其进行更改。如果可能,我真的希望避免以编程方式创建WkWebView。

注意:存在与此相关的问题(here),但是在那里接受的答案仅解决了实际程序的一部分(涉及添加用户脚本而不是配置)对象,因此无法添加自定义网址方案处理程序)。那里的其他答案都不能解决这个问题,因此我提出了另一个问题。

2 个答案:

答案 0 :(得分:0)

如何创建包含WKWebView的自定义视图。您可以在Storyboard中代替WKWebView使用此视图。

final class MyWebView: UIView {
    var webView: WKWebView!
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        let config = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: config)
        addSubview(webView)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        webView.frame = bounds
    }
}

要自定义情节提要中的其他属性,请将@IBInspectable添加到包装视图并将该值传递给内部配置。

下面的代码缺少情节提要中WKWebView的某些属性,但是  可以实现其他这样的属性。

final class MyWebView: UIView {
    @IBInspectable var userAgent: String?
    @IBInspectable var appName: String? {
        didSet {
            config.applicationNameForUserAgent = appName
        }
    }
    private var types: WKDataDetectorTypes = [
        .phoneNumber,
        .link,
        .address,
        .calendarEvent,
        .trackingNumber,
        .flightNumber,
        .lookupSuggestion
    ]
    @IBInspectable var phoneNumber: Bool = true {
        didSet {
            if phoneNumber {
                types.insert(.phoneNumber)
            } else {
                types.remove(.phoneNumber)
            }
            config.dataDetectorTypes = types
        }
    }
    @IBInspectable var link: Bool = true {
        didSet {
            if link {
                types.insert(.link)
            } else {
                types.remove(.link)
            }
            config.dataDetectorTypes = types
        }
    }
    @IBInspectable var address: Bool = true {
        didSet {
            if address {
                types.insert(.address)
            } else {
                types.remove(.address)
            }
            config.dataDetectorTypes = types
        }
    }
    @IBInspectable var calendarEvent: Bool = true {
        didSet {
            if calendarEvent {
                types.insert(.calendarEvent)
            } else {
                types.remove(.calendarEvent)
            }
            config.dataDetectorTypes = types
        }
    }
    @IBInspectable var trackingNumber: Bool = true {
        didSet {
            if trackingNumber {
                types.insert(.trackingNumber)
            } else {
                types.remove(.trackingNumber)
            }
            config.dataDetectorTypes = types
        }
    }
    @IBInspectable var flightNumber: Bool = true {
        didSet {
            if flightNumber {
                types.insert(.flightNumber)

            } else {
                types.remove(.flightNumber)
            }
            config.dataDetectorTypes = types
        }
    }
    @IBInspectable var lookupSuggestion: Bool = true {
        didSet {
            if phoneNumber {
                types.insert(.lookupSuggestion)
            } else {
                types.remove(.lookupSuggestion)

            }
            config.dataDetectorTypes = types
        }
    }
    @IBInspectable var javaScriptEnabled: Bool = true {
        didSet {
            config.preferences.javaScriptEnabled = javaScriptEnabled
        }
    }
    @IBInspectable var canAutoOpenWindows: Bool = false {
        didSet {
            config.preferences.javaScriptCanOpenWindowsAutomatically = canAutoOpenWindows
        }
    }

    lazy var webView: WKWebView = {
        let webView = WKWebView(frame: .zero, configuration: config)
        webView.customUserAgent = userAgent
        addSubview(webView)
        return webView
    }()
    private var config = WKWebViewConfiguration()

    override func layoutSubviews() {
        super.layoutSubviews()
        webView.frame = bounds
    }
}

答案 1 :(得分:-1)

所以,我做了一些测试:

@interface  ViewController  ()

@property   (strong)    IBOutlet    WKWebView   *webView ;

@end

@implementation ViewController

- (void)    awakeFromNib
{
    static  BOOL    hasBeenDone    = NO ;   //  because otherwise, awakeFromNib is called twice

    if (!hasBeenDone)
    {
        hasBeenDone = YES ;

        //  Create the scheme handler
        SchemeHandler           *mySchemeHandler    = [SchemeHandler new] ;
        NSLog(@"scheme handler : %lx",mySchemeHandler) ;

        if (!(self.webView))
        {
            //  Case 1 - we don't have a web view from the StoryBoard, we need to create it
            NSLog(@"Case 1") ;

            //  Add the scheme
            WKWebViewConfiguration  *configuration      = [WKWebViewConfiguration new] ;
            [configuration setURLSchemeHandler:mySchemeHandler
                              forURLScheme:@"stef"] ;

            //  Create and set the web view
            self.webView                                = [[WKWebView alloc] initWithFrame:NSZeroRect
                                                                             configuration:configuration] ;
        }
        else
        {
            //  Case 2 - we have a web view from the story board, just set the URL scheme handler
            //  of the configuration
            NSLog(@"Case 2") ;

            WKWebViewConfiguration  *configuration      = self.webView.configuration ;
            [configuration setURLSchemeHandler:mySchemeHandler
                              forURLScheme:@"stef"] ;
        }

        //  Log the view configuration
        NSLog(@"View configuration : %lx",self.webView.configuration) ;
        NSLog(@"URL handler for scheme : %lx",[self.webView.configuration     urlSchemeHandlerForURLScheme:@"stef"]) ;
    }
}


- (void)    viewDidLoad
{
    [super viewDidLoad] ;

    //  Log the view configuration
    NSLog(@"View configuration : %lx",self.webView.configuration) ;
    NSLog(@"URL handler for scheme : %lx",[self.webView.configuration urlSchemeHandlerForURLScheme:@"stef"]) ;

    //  Start loading a URL with the scheme - this should log "start" if everything works fine
    NSURL           *url        = [NSURL URLWithString:@"stef://willIWinTheBounty?"] ;
    NSURLRequest    *urlRequest = [NSURLRequest requestWithURL:url] ;
    [self.webView loadRequest:urlRequest] ;
}

@end

如果在情节提要中未设置IBOutlet webView的情况下运行该代码(案例1),则该代码将创建Web视图,为方案配置它,一切都很好。

  

方案处理程序:600000008e30

     

案例1

     

查看配置:600003d0c780

     

方案的网址处理程序:600000008e30

     

查看配置:600003d0c780

     

方案的网址处理程序:600000008e30

     

方案处理程序启动

如果在情节提要中设置了IBOutlet webView的情况下运行该代码(案例2),则setURLSchemeHandler:forURLScheme:实际上不起作用。在这种情况下,urlSchemeHandlerForURLScheme的日志将返回nil。

  

方案处理程序:600000005160

     

案例2

     

查看配置:600003d08d20

     

方案的网址处理程序:0

     

查看配置:600003d08d20

     

方案的网址处理程序:0

     

请注意,未调用方案处理程序启动

原因不是您通过getter获得了不同的副本,因为配置日志表明它保持不变。尽管调用了setURLSchemeHandler:forURLScheme,但只是没有设置方案处理程序。

因此,我想唯一的解决方案是使用案例1。根据您的视图设置,插入视图可能会或多或少地困难。我建议您在故事板上使用一个空的“母亲”视图,并使用以下代码:

@interface  ViewController  ()

@property   (weak)      IBOutlet    NSView      *webViewMother ;
@property   (strong)                WKWebView   *webView ;

@end


@implementation ViewController

- (void)    awakeFromNib
{
    static  BOOL    hasBeenDone    = NO ;   //  because otherwise, awakeFromNib is called twice

    if (!hasBeenDone)
    {
        hasBeenDone = YES ;

        //  Create the scheme handler
        SchemeHandler           *mySchemeHandler    = [SchemeHandler new] ;

        //  Create the configuration
        WKWebViewConfiguration  *configuration      = [WKWebViewConfiguration new] ;
        [configuration setURLSchemeHandler:mySchemeHandler
                          forURLScheme:@"stef"] ;

        //  Create the web view at the size of its mother view
    self.webView                                = [[WKWebView alloc]     initWithFrame:self.webViewMother.frame
                                                                         configuration:configuration] ;
        [self.webViewMother addSubview:self.webView] ;

    //  Log the view configuration
    NSLog(@"View configuration : %lx",self.webView.configuration) ;
    NSLog(@"URL handler for scheme : %lx",[self.webView.configuration     urlSchemeHandlerForURLScheme:@"stef"]) ;
    }

}

@end

对我来说很好,但是如果您有Web视图的子视图,则可能会很棘手。

  

查看配置:600003d082d0

     

方案的网址处理程序:600000004c90

     

查看配置:600003d082d0

     

方案的网址处理程序:600000004c90

     

方案处理程序启动

请注意,配置通过调用保持不变...

编辑:添加了运行日志