我需要传递一些额外的信息以及UIWebView loadRequest:
,以便它达到NSURLProtocol
的实现。信息无法绑定到NSURLRequest
,因为信息也必须与NSURLRequest mainDocumentURL
一起保留。所以我将NSURL
子类化并用它构造NSURLRequest
。我已经知道到达NSURLRequest
的{{1}}不是我已经提供给NSURLProtocol startLoading
的实例,所以我也实现了UIWebView loadRequest
,天真地期望URL加载系统会使用它
现在,NSURL copyWithZone
不会像人们合理预期的那样被召唤,但至少会在NSURLProtocol canInitWithRequest
之前被召唤4次。前两次,传入的startLoading
仍然包含我的自定义NSURLRequest
实现。然后,一个名为NSURL
的不幸内部代码会询问我的自定义CFURLCopyAbsoluteURL
的{{1}},而下一个absoluteURL
(以及之后的NSURL
)已经获得了全新canInitWithRequest
其中包含新的startLoading
{1}}。 <{1}}永远不会被调用,我的子类NSURLRequest
也会丢失。
在我放弃并实施一个劣质且脆弱的解决方案并将内容直接附加到URL字符串之前,我想问更高级别的向导,他们是否看到了如何捕获{{1的初始闪烁的方法雷达或如何欺骗NSURL
来携带我的自定义实例。我试图通过再次返回我的自定义NSURL类的新实例来破解copyWithZone
,但它没有帮助。我在NSURLProtocol setProperty
功能中看到了一些承诺,但现在看起来很无用。网址加载系统会愉快地创建所有内容的新实例,NSURL
到达NSURLProtocol
似乎与偶然输入CFURLCopyAbsoluteURL
的{{1}}相同。
更新:确定我希望尽可能缩短帖子,但即使是第一个回复也是要求技术背景,所以我们开始:我有多个{{1}在应用程序中。这些视图可以同时运行请求,绝对可以运行相同URL的请求。这就像桌面浏览器中的标签。但我需要区分哪个NSURL absoluteURL
是到达NSURLRequest
的每个特定NSURLProtocol
的来源。我需要每个URL请求都带有一个上下文。我不能简单地将网址映射到数据,因为多个UIWebView
可能随时加载相同的网址。
更新2:首选将上下文信息附加到UIWebView
,根据我的理解,这是唯一可用的。问题是页面内引用的资源请求(图像等)根本不会通过UIWebView
,而是直接在NSURLRequest
结束。我没有机会在NSURLProtocol
之前的任何地方触摸,检查或修改此类请求。此类请求的唯一上下文链接是UIWebViews
。
答案 0 :(得分:3)
如果有某种方法可以将原始NSURL
用作mainDocumentURL
,那将是理想的选择。如果没有办法阻止它被复制,我想到了以下黑客作为替代方案:
在将每个UIWebView
,set the user agent string创建为唯一值之前。据推测,此更改仅影响随后创建的UIWebView
个对象,因此每个视图最终都会显示自己独特的用户代理字符串。
在NSURLProtocol
实现中,您可以检查用户代理字符串以识别关联的UIWebView
,并使用实际的用户代理字符串将其传递给真实的协议处理程序(因此服务器将看不到任何内容)不同)。
所有这些都取决于真正以不同UA字符串结尾的视图。如果你设法让它发挥作用,请告诉我!
答案 1 :(得分: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:
的请求不同?我错过了另一个要求或怪癖吗?
答案 2 :(得分:1)
您可以通过自定义请求标头传递选项,假设目标网站或服务提供商不会以某种方式剥离传输中的选项。
可能会出现一种编码方案的挑战,该方案可以合理地编码为头字段值的ASCII字符串,然后解码为您想要的实际值。为此,自定义NSValueTransformer
似乎最合适。
答案 3 :(得分:0)
我遇到了同样的问题。我终于坚持马修建议的解决方案(使用用户代理字符串)。但是,由于解决方案没有充实,我添加了一个更详细的新答案。此外,我发现您不需要发送请求以使用户代理“坚持”。只需按照建议here通过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中的值(取自here)。
NSDictionary* userAgentDict = [NSDictionary dictionaryWithObjectsAndKeys:@"yourUserAgent", @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:userAgentDict];
(3)通过javascript获取新的用户代理字符串,如(1)中所做,但这次是在实际使用的webview实例上。
(4)将standardUserDefaults中的默认用户代理恢复为here。