WKWebView не будет открывать всплывающие окна входа в социальные сети

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

в viewDidLoad я попытался включить Javascript на init:

WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
WKPreferences *thePreferences = [[WKPreferences alloc] init];
thePreferences.javaScriptCanOpenWindowsAutomatically = YES;
thePreferences.javaScriptEnabled = YES;
theConfiguration.preferences = thePreferences;
self.wkWeb = [[WKWebView alloc] initWithFrame:screenRect configuration:theConfiguration];

Тем не менее, это не помогло мне. Затем я попытался сыграть с делегатами и пойти по этому пути. Я попытался поиграться с методом createWebViewWithConfiguration, но это кажется излишним, потому что мне пришлось отфильтровать, если они находятся по URL-адресу входа в систему, затем настроить всплывающее окно и отобразить его. И тогда это все еще не работало. Я также захожу сюда для логики основного кадра, если не, отменяю запрос и перезагружаю его в главном представлении, и это простое исправление в одну строку, где это вылилось в 20+ строк.

Это кажется общей проблемой, но я не могу найти много информации там. Есть идеи?

РЕДАКТИРОВАТЬ - Дополнение

Поиграв с ответом Армандса, я подхожу ближе. Теперь это мой метод createWebViewWithConfig, который просто отображает наложение белого экрана. Как будто мне нужно что-то сказать новому всплывающему окну для загрузки контента. Кроме того - я предполагаю, что могу поместить это модальное окно в мой текущий файл.m, и ему не нужен совершенно новый файл?

NSURL *url = navigationAction.request.URL;
if(!navigationAction.targetFrame.isMainFrame && [url.absoluteString rangeOfString:@"initiate_"].location != NSNotFound) {
    //open new modal webview
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.processPool = [appDelegate getSharedPool];

    self.popupLogin = [[WKWebView alloc] initWithFrame:self.wkWeb.bounds configuration:config];
    self.popupLogin.frame = CGRectMake(self.wkWeb.frame.origin.x,
                                       self.wkWeb.frame.origin.y,
                                       self.wkWeb.frame.size.width,
                                       self.wkWeb.frame.size.height);
    self.popupLogin.navigationDelegate = self;
    self.popupLogin.UIDelegate = self;
    [webView addSubview:self.popupLogin];
    [self.popupLogin loadRequest:navigationAction.request];
    return nil;
}

2 ответа

Решение

Эти кнопки входа в систему пытаются открыть новую вкладку, которая не поддерживается WKWebView. Насколько я знаю, есть только один способ сделать это.

Первое добавление WKUIDelegate метод:

-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
    NSURL *url = navigationAction.request.URL;
    if (navigationAction.targetFrame == nil && [url.absoluteString rangeOfString:@"facebook.com/dialog"].location != NSNotFound) {
        //Open new modal WKWebView
    }
    return nil;
}

В модальном WKWebView добавьте это:

-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
    NSURL *url = navigationResponse.response.URL;
    if ([url.absoluteString rangeOfString:@"close_popup.php"].location != NSNotFound) {
        //Close viewController
    }
    decisionHandler(WKNavigationResponsePolicyAllow);
}

close_popup.php для фейсбука. Если вам нужно поддерживать несколько социальных сетей, найдите что-то уникальное в их URL.

Для того, чтобы это работало, вам нужно будет обмениваться файлами cookie между WKWebViews. Для этого вы должны начать их с общим WKProcessPool, Я предпочитаю хранить его в AppDelegate.

WKWebView можно создать так:

- (void)createWebView
{
    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.processPool = delegate.webViewProcessPool;

    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
}

В AppDelegate просто лениво загружаем его:

-(id)webViewProcessPool
{
    if (!_webViewProcessPool) {
        _webViewProcessPool = [[WKProcessPool alloc] init];
    }
    return _webViewProcessPool;
}

Swift 4 и Swift 5

Создайте два экземпляра WKWebView

var webView : WKWebView!
var newWebviewPopupWindow: WKWebView?

Теперь реализуем методы

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        newWebviewPopupWindow = WKWebView(frame: view.bounds, configuration: configuration)
        newWebviewPopupWindow!.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        newWebviewPopupWindow!.navigationDelegate = self
        newWebviewPopupWindow!.uiDelegate = self
        view.addSubview(newWebviewPopupWindow!)
        return newWebviewPopupWindow!
    }

    func webViewDidClose(_ webView: WKWebView) {
        webView.removeFromSuperview()
        newWebviewPopupWindow = nil
    }

Также убедитесь, что эта строка находится в Info.plist, если ваш код все еще не работает.

 <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

Ответ Армандса на правильном пути, но может быть значительно улучшен.

  • Важно вернуть только что созданное веб-представление (а не ноль), если вы хотите, чтобы веб-просмотры могли работать друг с другом (например, через window.opener).
  • Совместное использование пула процессов происходит автоматически, если вы используете конфигурацию, переданную вызову create
  • Вам не нужны дополнительные проверки в вызове createWebViewWith. (Вы должны по-прежнему URL-адреса белого списка, если вы хотите предотвратить произвольные всплывающие окна или создать определенные типы WebViewController.)

В вашем главном WebViewController (где webView.uiDelegate = self):

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    let webView = WKWebView.init(frame: .zero, configuration: configuration)

    //OPTIONAL: check navigationAction.request.url to see what site is being opened as a popup

    //TODO HERE: Launch new instance of your WebViewController (within a nav controller)
    //and pass it this newly created webView to be added as main subview

    return webView
}

Вы все еще хотите иметь близкого слушателя в новом экземпляре вашего всплывающего WebViewController (где webView.navigationDelegate = self):

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    if let url = navigationResponse.response.url, url.absoluteString.hasPrefix("https://example.com/something-unique-to-this-popup-when-it-closes") {
        dismiss(animated: true, completion: nil)
    }
    decisionHandler(.allow)
}

Фрагмент Swift4/5 - использование MyWebView: расширенный WkWebView:

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration,
             for navigationAction: WKNavigationAction,
             windowFeatures: WKWindowFeatures) -> WKWebView? {
    if navigationAction.targetFrame == nil {
        let newView = MyWebView.init(frame: webView.frame, configuration: configuration)

        newView.customUserAgent = webView.customUserAgent
        newView.navigationDelegate = self
        newView.uiDelegate = self

        self.view.addSubview(newView)
        newView.fit(newView.superview!)

        newView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
        newView.configuration.preferences.javaScriptEnabled = true
        newView.configuration.preferences.plugInsEnabled = true
        newView.load(navigationAction.request)

        return newView
    }

Добавьте следующие обработчики, и всплывающее окно загрузится нормально.

# pragma mark WKUIDelegate
- (nullable WKWebView *)webView:(WKWebView *)webView
createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures
(WKWindowFeatures *)windowFeatures
{
if (navigationAction.targetFrame == nil) {
    _popupWebViewObject = [[WKWebView alloc] initWithFrame:webView.frame configuration:configuration];
    _popupWebViewObject.customUserAgent = webView.customUserAgent;
    _popupWebViewObject.UIDelegate = self;
    _popupWebViewObject.navigationDelegate = self;
    [self.window.contentView addSubview:_popupWebViewObject];
    _popupWebViewObject.configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES;
    _popupWebViewObject.configuration.preferences.javaScriptEnabled = YES;
    _popupWebViewObject.configuration.preferences.plugInsEnabled = YES;
    [_popupWebViewObject loadRequest:[navigationAction.request copy]];
    return _popupWebViewObject;
}
return nil;
}

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"%s", __FUNCTION__);
    NSLog(@"%@ TOKEN : ",webView.URL.absoluteString.lowercaseString);
    [self dismissPopWindow:webView];
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    [self dismissPopWindow:webView];
    decisionHandler(WKNavigationActionPolicyAllow);
}
Другие вопросы по тегам