首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >为从Nib或Storyboard生成的WKWebViewConfiguration设置自定义WKWebView

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

Stack Overflow用户
提问于 2019-05-31 20:28:15
回答 2查看 6.5K关注 0票数 2

我想对我的应用程序使用自定义URL方案,但在配置URL方案时遇到了问题。

当我以编程方式创建WKWebView对象时(使用initWithFrame:.)我能够指定自己的WKWebViewConfiguration对象,但是当Nib/Storyboard中的WKWebView被自动创建时(通过initWithCoder:),我无法指定配置。配置是只读的,所以我不能在事实发生后更改它。如果可能的话,我非常希望避免以编程的方式创建WkWebView。

注意:有一个与此相关的现有问题(https://stackoverflow.com/questions/48451264/set-wkwebviewconfiguration-on-wkwebview-from-nib-or-storyboard),但在那里接受的答案只解决了实际程序的一个子集(它涉及添加用户脚本而不是配置对象,因此不能添加自定义的URL方案处理程序)。那里的其他答案要么无助于这个问题,所以我又提出了另一个问题。

更新:根据我收到的评论,我想在此作一些澄清。

WKWebViewConfiguration是一个“复制”属性,如下所定义:

*@属性(非原子、只读、复制) WKWebViewConfiguration配置;

我试着把它打印了好几遍,我发现它正在改变:

2019年-05-30 15:02:25.724312-0700 MyTest 916:72204配置= 0x101b06b50 2019年-05-30 15:02:25.724499-0700 MyTest 916:72204配置= 0x101a37110

使用LLDB得到相同的结果(每次不同):

打印self configuration $17 = 0x0000000102e0b990 打印self configuration $18 = 0x0000000102f3bd40

EN

回答 2

Stack Overflow用户

发布于 2019-06-12 09:40:21

创建一个包含WKWebView的自定义视图如何?您可以在Storyboard中使用此视图而不是WKWebView。

代码语言:javascript
代码运行次数:0
运行
复制
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
    }
}

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

下面的代码缺少故事板中WKWebView所具有的一些属性,但是可以实现类似于此的其他属性。

代码语言:javascript
代码运行次数:0
运行
复制
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
    }
}
票数 0
EN

Stack Overflow用户

发布于 2019-06-05 19:26:57

所以,我做了一些测试

代码语言:javascript
代码运行次数:0
运行
复制
@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 unset运行该代码(案例1),则代码将创建web视图,将其配置为方案,一切都很好。

方案处理程序: 600000008e30 案例1 视图配置: 600003d0c780 方案的URL处理程序: 600000008e30 视图配置: 600003d0c780 方案的URL处理程序: 600000008e30 方案处理程序启动

如果您在情节提要中使用IBOutlet webView集运行该代码(案例2),那么setURLSchemeHandler:forURLScheme:确实无法工作。在这种情况下,urlSchemeHandlerForURLScheme:返回零的日志。

方案处理程序: 600000005160 案例2 视图配置: 600003d08d20 方案的URL处理程序:0 视图配置: 600003d08d20 方案的URL处理程序:0 注意,方案处理程序start不被调用。

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

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

代码语言:javascript
代码运行次数:0
运行
复制
@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

对我来说工作很好,但是如果你有你的网页视图的子视图的话,可能会很棘手。

视图配置: 600003d082d0 方案的URL处理程序: 600000004c90 视图配置: 600003d082d0 方案的URL处理程序: 600000004c90 方案处理程序启动

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

编辑:添加了运行日志

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56401374

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档