UIWebViewDelegate不监控XMLHttpRequest?
UIWebViewDelegate是否真的不监视使用XMLHttpRequest所做的请求? 如果是这样,有没有办法监测这种请求?
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSMutableURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
; -(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSMutableURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
var xhr = new XMLHttpRequest(); xhr.open("GET", "http://www.google.com", true); xhr.onreadystatechange=function() { if (xhr.readyState==4) { alert(xhr.responseText); } } xhr.send();
有趣的问题。
有两个部分使这个工作:一个JavaScript处理程序和UIWebView委托方法。 在JavaScript中,我们可以修改原型方法来在创buildAJAX请求时触发事件。 用我们的UIWebView委托,我们可以捕获这些事件。
JavaScript处理程序
我们需要在AJAX请求发出时得到通知。 我在这里find了解决scheme。
在我们的例子中,为了使代码正常工作,我把下面的JavaScript放在一个名为ajax_handler.js的资源中,这个资源与我的应用程序捆绑在一起。
var s_ajaxListener = new Object(); s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open; s_ajaxListener.tempSend = XMLHttpRequest.prototype.send; s_ajaxListener.callback = function () { window.location='mpAjaxHandler://' + this.url; }; XMLHttpRequest.prototype.open = function(a,b) { if (!a) var a=''; if (!b) var b=''; s_ajaxListener.tempOpen.apply(this, arguments); s_ajaxListener.method = a; s_ajaxListener.url = b; if (a.toLowerCase() == 'get') { s_ajaxListener.data = b.split('?'); s_ajaxListener.data = s_ajaxListener.data[1]; } } XMLHttpRequest.prototype.send = function(a,b) { if (!a) var a=''; if (!b) var b=''; s_ajaxListener.tempSend.apply(this, arguments); if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a; s_ajaxListener.callback(); }
这实际上是做的是将浏览器的位置改变成一些URLscheme(在这种情况下, mpAjaxHandle )与关于请求的信息。 别担心,我们的代表抓住这个,位置不会改变。
UIWebView委托
首先,我们需要阅读我们的JavaScript文件。 我build议把它存储在一个静态variables。 我习惯于使用+初始化。
static NSString *JSHandler; + (void)initialize { JSHandler = [[NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ajax_handler" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil] retain]; }
接下来,我们希望在加载完页面之前注入这个JavaScript,以便我们可以接收所有事件。
- (void)webViewDidStartLoad:(UIWebView *)webView { [webView stringByEvaluatingJavaScriptFromString:JSHandler]; }
最后,我们要捕捉事件。
由于URLscheme是由我们构成的,所以我们不想实际上遵循它。 我们返回NO ,一切都很好。
#define CocoaJSHandler @"mpAjaxHandler" - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if ([[[request URL] scheme] isEqual:CocoaJSHandler]) { NSString *requestedURLString = [[[request URL] absoluteString] substringFromIndex:[CocoaJSHandler length] + 3]; NSLog(@"ajax request: %@", requestedURLString); return NO; } return YES; }
我用解决scheme创build了一个示例项目,但无处容纳。 你可以通过邮件告诉我,如果你可以托pipe它,我会相应地编辑这篇文章。
你可以使用NSURLProtocol。 例如,如果你用http://localhost/path
调用XMLHttpRequest,你可以用下面的方法处理它:
@interface YourProtocol: NSURLProtocol
然后执行:
+ (BOOL)canInitWithRequest:(NSURLRequest *)request { return [request.URL.host isEqualToString:@"localhost"]; } + (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request { return request; } - (void) startLoading { // Here you handle self.request } - (void)stopLoading { }
您需要注册协议如下:
[NSURLProtocol registerClass:[YourProtocol class]];
通过实现和注册NSURLProtocol的子类,您可以捕获您的UIWebView的所有请求。 在某些情况下,这可能是矫枉过正,但如果你不能修改实际运行的JavaScript,那么这是最好的select。
在我的情况下,我需要捕获所有的请求,并插入一个特定的HTTP头到他们每一个。 我通过实现NSURLProtocol来完成这个工作,如果请求对应于我感兴趣的URL,则使用registerClass注册它,然后在我的子类中回答YES(+ BOOL)canInitWithRequest:(NSURLRequest *)请求。然后,您必须实现其他方法的协议,这可以通过使用NSURLConnection,设置协议类作为委托,并将NSURLConnection的委托方法redirect到NSURLProtocolClient
这似乎是真的。 没有办法监视UIWebView所做的除UIWebViewDelegate提供的function外,除非您可以找出使用stringByEvaluatingJavaScriptFromString:
注入一些Javascript来执行所需的操作。
正如其他人所提到的,UIWebViewDelegate仅观察window.location和iframe.src的更改。
如果您只想使用iOS自定义urlscheme,则可以像这样使用<iframe>
。
例如,如果你想这样调用一个URL Scheme
objc://my_action?arg1=1&arg2=2
在你的js文件中:
/** * @param msg : path of your query * @param data : arguments list of your query */ var call_url = function(msg, data){ const scheme = "objc"; var url = scheme + '://' + msg; if(data){ var pstr = []; for(var k in data) if(typeof data[k] != 'function') pstr.push(encodeURIComponent(k)+"="+encodeURIComponent(data[k])); url += '?'+pstr.join('&'); } var i = document.createElement("iframe"); i.src = url; i.style.opacity=0; document.body.appendChild(i); setTimeout(function(){i.parentNode.removeChild(i)},200); } //when you call this custom url scheme call_url ("my_action", {arg1:1,arg2:2});