6

我需要传递一些额外的信息,UIWebView loadRequest:以便它达到我的NSURLProtocol. 信息不能绑定,NSURLRequest因为信息也必须保留NSURLRequest mainDocumentURL。所以我用它进行子类化NSURL和构建NSURLRequest。我已经知道NSURLRequestwhichreachNSURLProtocol startLoading不是我提供给的实例UIWebView loadRequest,所以我也实现NSURL copyWithZone了,天真地期待 URL 加载系统会使用它。

现在,NSURLProtocol canInitWithRequest不是像人们合理预期的那样被调用一次,而是在之前至少被调用了 4 次startLoading。前 2 次,传入的NSURLRequest仍然包含我的自定义NSURL实现。然后一个不幸的内部代码CFURLCopyAbsoluteURL要求absoluteURL我的自定义NSURL和下一个canInitWithRequest(和后续startLoading的)已经获得了一个全新NSURLRequest的全新NSURLcopyWithZone永远不会被调用,并且我的子类NSURL丢失了。

在我放弃并实施一个将东西直接附加到 URL 字符串的劣质且脆弱的解决方案之前,我想问问更高级别的向导,他们是否找到了一种方法来捕捉NSURLProtocol雷达上的初始闪烁或如何CFURLCopyAbsoluteURL欺骗携带我的自定义实例。我试图NSURL absoluteURL通过再次返回我的自定义 NSURL 类的新实例来破解,但它没有帮助。我已经看到了一些NSURLProtocol setProperty功能上的承诺,但现在它似乎毫无用处。URL加载系统愉快地创建了一切的新实例,并且NSURLRequest到达NSURLProtocol似乎与UIWebView偶然输入的相同。

更新:好的,我想让帖子尽可能短,但即使是第一个回复也要求提供技术背景,所以我们开始吧:我UIWebView在 app 中有多个 s。这些视图可以同时运行请求,并且绝对可以运行相同 URL 的请求。它就像桌面浏览器中的选项卡。但我需要区分UIWebView每个特定NSURLRequest到达的来源NSURLProtocol。我需要每个 URL 请求都携带一个上下文。我不能简单地将 URL 映射到数据,因为多个UIWebViews可能随时加载相同的 URL。

更新 2:附加上下文信息NSURL是首选,据我所知,这是唯一可用的。问题是对页面内引用的资源(图像等)的请求根本没有通过UIWebViewDelegateNSURLProtocol直接进入。在NSURLProtocol. 此类请求的唯一上下文链接是它们的NSURLRequest mainDocumentURL.

4

4 回答 4

3

如果有某种方法可以NSURL使用您的原件,mainDocumentURL那将是理想的。如果没有办法防止它被复制,我想到了以下 hack 作为替代方案:

在创建 each 之前UIWebView将用户代理字符串设置为唯一值。假设此更改仅影响UIWebView随后创建的对象,因此每个视图都会以自己独特的用户代理字符串结束。

NSURLProtocol实现中,您可以检查用户代理字符串以识别关联UIWebView并使用实际的用户代理字符串将其传递给真正的协议处理程序(因此服务器不会看到任何不同)。

所有这些都取决于最终以不同 UA 字符串结尾的视图。如果你设法让它工作,请告诉我!

于 2013-10-31T07:50:46.867 回答
1

你说你不能把它放在 上NSURLRequest,但我从你更新的讨论中不清楚为什么。那将是最自然的放置位置。

  • 实施webView:shouldLoadWithRequest:navigationType:
  • 使用 将额外的属性附加到提供的请求objc_setAssociatedObject。然后返回YES。(在这里使用会很好setProperty:forKey:inRequest:,但是UIWebView会传递给我们一个不可变的请求,所以我们只能附加关联的对象。另一种方式UIWebView是 OS X 的苍白阴影WebView,它可以处理这个问题)。
  • 在 中NSProtocol,使用 读取您的额外属性objc_getAssociatedObject。该请求应该与您之前提出的请求相同。你认为情况并非如此。您是说在的请求与在webView:shouldLoadWithRequest:navigationType:的请求不同initWithRequest:cachedResponse:client:吗?

我是否缺少其他要求或怪癖?

于 2013-10-30T20:49:23.070 回答
1

您可以通过自定义请求标头传递选项,假设目标网站或服务提供商不会以某种方式剥离传输中的选项。

挑战在于提出一种编码方案,该方案可以合理地编码为标头字段值的 ASCII 字符串,然后解码为您想要的实际值。为此,一个习俗NSValueTransformer似乎是最合适的。

于 2013-11-11T18:22:20.707 回答
0

我有同样的问题。我终于坚持使用 Matthew 建议的解决方案(使用用户代理字符串)。但是,由于解决方案没有充实,我添加了一个包含更多细节的新答案。此外,我发现您不需要发送请求来使用户代理“粘住”。按照这里的建议通过 javascript 就足够了。

以下步骤对我有用:

(1) 获取当前的默认用户代理。稍后您需要将其放回 NSURLProtocol 中的请求中。您需要使用新的 webview insatnce,因为获取用户代理会使其粘在 webview 上,因此您以后无法更改它。

UIWebView* myWebview = [[UIWebView alloc] init];
NSString* defaultUserAgent = [myWebview stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
[myWebview release]; // no needed with ARC, but to emphasize, that the webview instance is not needed anymore

(2) 更改standardUserDefaults 中的值(取自此处)。

NSDictionary* userAgentDict = [NSDictionary dictionaryWithObjectsAndKeys:@"yourUserAgent", @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:userAgentDict];

(3) 使新的用户代理字符串粘在您的 webView 上,方法是像 (1) 中所做的那样通过 javascript 获取它,但这次是在您实际使用的 webview 实例上。

(4) 恢复 standardUserDefaults 中的默认用户代理,如此处所示

于 2014-07-25T14:54:31.357 回答