Какао / WebKit, имеющий «window.open ()» ссылки JavaScript, открывающиеся в экземпляре Safari - PullRequest
7 голосов
/ 07 ноября 2008

Я создаю действительно базовое приложение Cocoa, используя WebKit, для отображения в нем приложения Flash / Silverlight. Очень простой, нет намерений, чтобы это был сам браузер.

До сих пор мне удавалось заставить его открывать базовые html-ссылки (<a href="..." />) в новом экземпляре Safari с помощью

[[NSWorkspace sharedWorkspace] openURL:[request URL]];

Теперь моя проблема заключается в открытии ссылки в новом экземпляре Safari, когда window.open() используется в JavaScript. Я «думаю» (и этим я взломал код и не уверен, действительно ли я это сделал), я получил такую ​​работу, установив policyDelegate WebView и реализовав

-webView:decidePolicyForNavigationAction:request:frame:decisionListener:

метод делегата. Однако это привело к непредсказуемому поведению.

Итак, простой вопрос: что мне нужно сделать, чтобы при вызове window.open() ссылка открывалась в новом экземпляре Safari.

Спасибо

Главное, я обычно являюсь разработчиком .NET и работаю с Cocoa / WebKit всего несколько дней.

Ответы [ 7 ]

9 голосов
/ 07 ноября 2008

Я сделал успехи прошлой ночью и определил часть моей проблемы.

Я уже использую webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:, и я заставил его работать с тегами привязки, однако кажется, что метод никогда не вызывается при вызове JavaScript.

Однако, когда вызывается window.open(), вызывается webView:createWebViewWithRequest:request, я пытался заставить окно открываться в Safari здесь, однако запрос всегда нулевой. Так что я никогда не смогу прочитать URL.

Я провел некоторые поиски, и это, кажется, известное " misfeature ", однако я не смог найти способ обойти это.

Насколько я понимаю, createWebViewWithRequest дает вам возможность создать новое веб-представление, затем запрошенный URL-адрес отправляется в новый веб-просмотр для загрузки. Это лучшее объяснение, которое мне удалось найти.

Итак, хотя многие люди указывали на эту проблему, мне еще предстоит найти какое-либо решение, которое соответствует моим потребностям. Я попытаюсь еще немного углубиться в decidePolicyForNewWindowAction.

Спасибо!

6 голосов
/ 04 февраля 2009

Ну, я справляюсь с этим, создавая фиктивный веб-вид, устанавливая его делегат frameLoad в пользовательский класс, который обрабатывает

- (void)webView:decidePolicyForNavigationAction:actionInformation :request:frame:decisionListener:

и открывает там новое окно.

код:

- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
    //this is a hack because request URL is null here due to a bug in webkit        
    return [newWindowHandler webView];
}

и NewWindowHandler:

@implementation NewWindowHandler

-(NewWindowHandler*)initWithWebView:(WebView*)newWebView {
    webView = newWebView;

    [webView setUIDelegate:self];
    [webView setPolicyDelegate:self];  
    [webView setResourceLoadDelegate:self];

    return self;
}

- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
    [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]];
}

-(WebView*)webView {
    return webView;
}
4 голосов
/ 13 марта 2013

Кажется, есть ошибка с webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener: в том, что запрос всегда nil, но есть надежное решение, которое работает как с обычными target="_blank" ссылками, так и с javascript.

В основном я использую другой эфемерный WebView для обработки загрузки новой страницы. Похож на Yoni Shalom, но с немного более синтаксическим сахаром.

Чтобы использовать его, сначала установите объект делегата для вашего WebView, в этом случае я устанавливаю себя в качестве делегата:

webView.UIDelegate = self;

Затем просто реализуйте метод делегата webView:createWebViewWithRequest: и используйте мой блочный API, чтобы что-то делать при загрузке новой страницы, в этом случае я открываю страницу во внешнем браузере:

-(WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
    return [GBWebViewExternalLinkHandler riggedWebViewWithLoadHandler:^(NSURL *url) {
        [[NSWorkspace sharedWorkspace] openURL:url];
    }];
}

Вот и все. Вот код для моего класса. Заголовок:

//  GBWebViewExternalLinkHandler.h
//  TabApp2
//
//  Created by Luka Mirosevic on 13/03/2013.
//  Copyright (c) 2013 Goonbee. All rights reserved.
//

#import <Foundation/Foundation.h>

@class WebView;

typedef void(^NewWindowCallback)(NSURL *url);

@interface GBWebViewExternalLinkHandler : NSObject

+(WebView *)riggedWebViewWithLoadHandler:(NewWindowCallback)handler;

@end

реализация:

//  GBWebViewExternalLinkHandler.m
//  TabApp2
//
//  Created by Luka Mirosevic on 13/03/2013.
//  Copyright (c) 2013 Goonbee. All rights reserved.
//

#import "GBWebViewExternalLinkHandler.h"

#import <WebKit/WebKit.h>

@interface GBWebViewExternalLinkHandler ()

@property (strong, nonatomic) WebView                           *attachedWebView;
@property (strong, nonatomic) GBWebViewExternalLinkHandler      *retainedSelf;
@property (copy, nonatomic) NewWindowCallback                   handler;

@end

@implementation GBWebViewExternalLinkHandler

-(id)init {
    if (self = [super init]) {
        //create a new webview with self as the policyDelegate, and keep a ref to it
        self.attachedWebView = [WebView new];
        self.attachedWebView.policyDelegate = self;
    }

    return self;
}

-(void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
    //execute handler
    if (self.handler) {
        self.handler(actionInformation[WebActionOriginalURLKey]);
    }

    //our job is done so safe to unretain yourself
    self.retainedSelf = nil;
}

+(WebView *)riggedWebViewWithLoadHandler:(NewWindowCallback)handler {
    //create a new handler
    GBWebViewExternalLinkHandler *newWindowHandler = [GBWebViewExternalLinkHandler new];

    //store the block
    newWindowHandler.handler = handler;

    //retain yourself so that we persist until the webView:decidePolicyForNavigationAction:request:frame:decisionListener: method has been called
    newWindowHandler.retainedSelf = newWindowHandler;

    //return the attached webview
    return newWindowHandler.attachedWebView;
}

@end

Лицензия Apache 2.

2 голосов
/ 10 декабря 2013

Прочитав все посты, я нашел свое простое решение, все функи находятся в одном классе, вот он, открывает ссылку в браузере.

- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {

    return [self externalWebView:sender];
}




- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
{
    [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]];
}

-(WebView*)externalWebView:(WebView*)newWebView
{
     WebView *webView = newWebView;

    [webView setUIDelegate:self];
    [webView setPolicyDelegate:self];
    [webView setResourceLoadDelegate:self];
    return webView;
}
2 голосов
/ 07 ноября 2008

Вы не упоминаете, какое странное поведение вы видите. Быстрая возможность состоит в том, что при реализации метода делегата вы забыли сообщить веб-представлению, что игнорируете щелчок, вызывая метод игнорирования WebPolicyDecisionListener , который был передан вашему делегату, что, возможно, поместило вещи в странное состояние.

Если это не проблема, то насколько вы контролируете контент, который вы отображаете? Делегат политики предоставляет вам простые механизмы для фильтрации всех нагрузок на ресурсы (как вы обнаружили), и все новые окна открываются через webView: managePolicyForNewWindowAction: request: newFrameName: SolutionListener: . Все вызовы window.open должны проходить через это, как и все, что вызывает новое окно.

Если есть другие открытые окна, которые вы хотите оставить внутри своего приложения, вам придется проделать еще немного работы. Одним из аргументов, передаваемых делегату, является словарь, содержащий информацию о событии. В этом словаре WebActionElementKey будет иметь словарь, содержащий количество деталей , включая исходное содержимое ссылки dom. Если вы хотите покопаться там, вы можете взять фактический элемент DOM и проверить текст href, чтобы увидеть, начинается ли он с window.open. Это немного тяжелый вес, но если вам нужен мелкозернистый контроль, он вам это даст.

0 голосов
/ 24 августа 2015

В качестве альтернативы возвращению нового WebView и ожидания вызова его метода loadRequest: я переписал функцию window.open в JSContext WebView:

Во-первых, я установил свой контроллер как WebFrameLoadDelegate для WebView:

myWebView.frameLoadDelegate = self;

Затем в методе делегата я переписал функцию window.open и вместо этого могу обработать URL.

- (void)webView:(WebView *)webView didCreateJavaScriptContext:(JSContext *)context forFrame:(WebFrame *)frame{
context[@"window"][@"open"] = ^(id url){
        NSLog(@"url to load: %@", url);
    };
}

Это позволило мне обработать запрос, как мне было нужно, без неловкой необходимости создавать дополнительные WebView.

0 голосов
/ 07 ноября 2014

Пояснение:

Windows, созданные из JavaScript через window.open, проходят через createWebViewWithRequest. Все вызовы window.open приводят к созданию createWebViewWithRequest: с нулевым запросом, а затем с изменением расположения в этом WebView.

Для получения дополнительной информации, см. Этот старый пост в списке рассылки WebKit.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...