我想对我的应用程序使用自定义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
发布于 2019-06-12 01:40:21
创建一个包含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
}
}
若要自定义Storyboard中的其他属性,请将@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
}
}
发布于 2019-06-05 11:26:57
所以,我做了一些测试
@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。根据您的视图设置,插入视图可能或多或少是困难的。我建议在您的故事板上有一个空的“母亲”视图,并使用以下代码:
@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 方案处理程序启动
请注意,通过调用,配置保持不变。
编辑:添加了运行日志
https://stackoverflow.com/questions/56401374
复制