7

我正在使用 WebKit 构建一个非常基本的 Cocoa 应用程序,以在其中显示一个 Flash/Silverlight 应用程序。非常基本,无意让它成为浏览器本身。

到目前为止,我已经能够使用它<a href="..." />在 Safari 的新实例中打开基本的 html 链接 ()

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

window.open()现在我的困难是在 JavaScript 中使用时在新的 Safari 实例中打开链接。我“认为”(通过这个,我一直在破解代码并且不确定我是否真的这样做了)我通过设置 WebViewpolicyDelegate并实现它来实现这种工作

-webView:decidePolicyForNavigationAction:request:frame:decisionListener:

委托方法。然而,这导致了一些不稳定的行为。

所以一个简单的问题,我需要做什么才能在window.open()被调用时在 Safari 的新实例中打开链接。

谢谢

重要的是,我通常是一名 .NET 开发人员,并且只使用 Cocoa/WebKit 几天。

4

7 回答 7

9

昨晚我取得了进步,并解决了我的部分问题。

我已经在使用webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:并且已经让它与锚标记一起使用,但是当调用 JavaScript 时,该方法似乎从未被调用。

但是,当window.open()被调用时webView:createWebViewWithRequest:request,我试图在此处强制窗口在 Safari 中打开,但是请求始终为空。所以我永远无法读出 URL。

我已经进行了一些搜索,这似乎是一个已知的“错误功能”,但是我无法找到解决它的方法。

据我了解createWebViewWithRequest,您可以创建新的 webview,然后将请求的 url 发送到要加载的新 webview。 这是迄今为止我能找到的最好的解释。

因此,虽然很多人已经指出了这个问题,但我还没有看到任何适合我需要的解决方案。我会尝试再深入一点decidePolicyForNewWindowAction

谢谢!

于 2008-11-07T16:02:55.710 回答
6

好吧,我通过创建一个虚拟 webView 来处理它,将它的 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;
}
于 2009-02-04T10:20:31.713 回答
4

似乎有一个错误,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。

于 2013-03-13T10:17:05.687 回答
2

通过阅读所有帖子,我想出了我的简单解决方案,所有功能都在同一个类中,在这里,用浏览器打开一个链接。

- (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;
}
于 2013-12-09T21:42:19.637 回答
2

你没有提到你看到什么样的不稳定行为。一种快速的可能性是,在实现委托方法时,您忘记通过调用传递给您的委托的WebPolicyDecisionListener的忽略方法来告诉 webview 您忽略了单击,这可能会使事情进入一个奇怪的状态。

如果这不是问题,那么您对所显示的内容有多少控制权?策略委托为您提供了过滤所有资源负载的简单机制(正如您所发现的那样),并且所有新窗口都通过webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:打开。所有 window.open 调用都应该通过它,触发新窗口的其他任何东西也应该如此。

如果您想在应用程序中保留其他打开的窗口,您将做更多的工作。传递给委托的参数之一是包含有关事件信息的字典。Insie 那个字典 WebActionElementKey 将有一个包含许多细节的字典,包括链接的原始 dom 内容。如果你想在那里四处寻找,你可以获取实际的 DOM 元素,并检查 href 的文本以查看它是否以 window.open 开头。这有点重,但如果你想要细粒度的控制,它会给你。

于 2008-11-07T10:30:59.947 回答
0

解释:

通过 window.open 从 JavaScript 创建的 Windows 通过 createWebViewWithRequest。所有 window.open 调用都会导致 createWebViewWithRequest: 请求为空,然后在该 WebView 上发生位置更改。

有关详细信息,请参阅WebKit 邮件列表上的这篇旧帖子。

于 2014-11-07T04:58:05.260 回答
0

除了返回一个新的 WebView 并等待其loadRequest:方法被调用之外,我最终覆盖window.open了 WebView 的 JSContext 中的函数:

首先,我将我的控制器设置为 WebView 的 WebFrameLoadDelegate:

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。

于 2015-08-24T03:41:49.810 回答