Настройка пользовательской конфигурации WKWebViewConfiguration для WKWebView, созданной из Nib или Storyboard - PullRequest
1 голос
/ 31 мая 2019

Я хотел бы использовать пользовательскую схему URL для своего приложения, но у меня возникли проблемы с настройкой схемы URL.

Когда я создаю объект WKWebView программно (с initWithFrame: ...), я могу указать свой собственный объект WKWebViewConfiguration, но когда WKWebView в Nib / Storyboard создается автоматически (через initWithCoder :), я не могууказать конфигурацию.Конфигурация доступна только для чтения, поэтому я не могу изменить ее после факта.Я действительно предпочел бы избегать создания WkWebView программно, если это возможно.

Примечание: есть существующий вопрос, связанный с этим ( здесь ), но ответ, который был принят только тамрешает подмножество фактической программы (это включает добавление пользовательского сценария вместо объекта конфигурации, поэтому нельзя добавить обработчик пользовательской схемы URL).Другие ответы там тоже не помогают с этой проблемой, поэтому я открыл еще один вопрос.

Обновление: я хотел дать некоторые пояснения здесь на основе полученного комментария.

WKWebViewConfigurationэто свойство «copy», как определено здесь:

* @ свойство (неатомное, только для чтения, копирование) WKWebViewConfiguration configuration;

Я пытался распечатать его несколько рази я вижу, что он меняется:

2019-05-30 15: 02: 25.724312-0700 MyTest [916: 72204] конфигурация = 0x101b06b50

2019-05-30 15:02: 25.724499-0700 MyTest [916: 72204] configuration = 0x101a37110

Использование LLDB дает одинаковый результат (каждый раз отличается):

(lldb) print [selfконфигурация] (WKWebViewConfiguration *) $ 17 = 0x0000000102e0b990

(lldb) печать [самостоятельная конфигурация] (WKWebViewConfiguration *) $ 18 = 0x0000000102f3bd40

Ответы [ 2 ]

0 голосов
/ 12 июня 2019

Как насчет создания пользовательского представления, содержащего WKWebView.Вы можете использовать это представление в раскадровке вместо 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
    }
}
0 голосов
/ 05 июня 2019

Итак, я сделал несколько тестов:

@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), то код создает веб-представление, настраивает его для схемы и все в порядке.

обработчик схемы: 600000008e30

Дело 1

Просмотр конфигурации: 600003d0c780

Обработчик URL для схемы: 600000008e30

Просмотр конфигурации: 600003d0c780

Обработчик URL для схемы: 600000008e30

схема запуска обработчика

Если вы запускаете этот код с веб-представлением IBOutlet, установленным в раскадровке (случай 2), то действительно, setURLSchemeHandler: forURLScheme: не работает. Журнал urlSchemeHandlerForURLScheme: в этом случае возвращает nil.

обработчик схемы: 600000005160

Дело 2

Просмотр конфигурации: 600003d08d20

Обработчик URL для схемы: 0

Просмотр конфигурации: 600003d08d20

Обработчик URL для схемы: 0

Обратите внимание, что запуск обработчика схемы не называется

Причина не в том, что вы получаете другую копию через геттер, так как журнал конфигурации показывает, что она остается прежней. Просто обработчик схемы не установлен, несмотря на вызов 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

схема запуска обработчика

Обратите внимание, что конфигурация остается неизменной посредством вызовов ...

Редактировать: добавлены журналы запуска

...