UIWebViewDelegate不监控XMLHttpRequest?

Thy*_*hys 53 ajax xcode xmlhttprequest uiwebview

是否真的UIWebViewDelegate不监视使用XMLHttpRequest发出的请求?如果是这样,有没有办法监控这类请求?

例如,UIWebViewDelegate没有捕获到它-(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();
Run Code Online (Sandbox Code Playgroud)

小智 80

有趣的问题.

有两个部分可以完成这项工作:JavaScript处理程序和UIWebView委托方法.在JavaScript中,我们可以修改原型方法,以在创建AJAX请求时触发事件.通过我们的UIWebView委托,我们可以捕获这些事件.

JavaScript处理程序

我们需要在发出AJAX请求时收到通知.我在这里找到了解决方案.

在我们的例子中,为了使代码工作,我将以下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();
}
Run Code Online (Sandbox Code Playgroud)

这将实际做的是将浏览器的位置更改为某些组成的URL方案(在本例中为mpAjaxHandle),其中包含有关请求的信息.不用担心,我们的代表抓住这个并且位置不会改变.

UIWebView委托

首先,我们需要阅读我们的JavaScript文件.我建议将它存储在一个静态变量中.我习惯使用+初始化.

static NSString *JSHandler;

+ (void)initialize {
    JSHandler = [[NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ajax_handler" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil] retain];
}
Run Code Online (Sandbox Code Playgroud)

接下来,我们希望在页面加载之前注入此JavaScript,以便我们可以接收所有事件.

- (void)webViewDidStartLoad:(UIWebView *)webView {
    [webView stringByEvaluatingJavaScriptFromString:JSHandler];
}
Run Code Online (Sandbox Code Playgroud)

最后,我们想捕捉这个事件.

由于URL方案已经完成,我们不希望实际遵循它.我们返回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;
}
Run Code Online (Sandbox Code Playgroud)

我用解决方案创建了一个示例项目但无处可托管它.如果你可以托管我,你可以给我留言,我会相应地编辑这篇文章.

  • 请注意,XCode不会自动将包含扩展名.js的文件添加到捆绑包中.您需要手动添加文件. (2认同)
  • 注意我只是将JS样本直接打入NSString进行测试,但最初没有用.我不得不加一个; 在XMLHttpRequest.prototype.send/open赋值的尾随之后. (2认同)
  • 另请注意,即使JS运行/评估两次,我在整个批次中添加了一个if(!s_ajaxListener),它继续工作. (2认同)

Geo*_*rge 20

您可以使用NSURLProtocol.例如,如果您调用XMLHttpRequest,则http://localhost/path可以使用以下方法处理它:

@interface YourProtocol: NSURLProtocol
Run Code Online (Sandbox Code Playgroud)

然后为实施:

+ (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
{
}
Run Code Online (Sandbox Code Playgroud)

您需要按如下方式注册协议:

    [NSURLProtocol registerClass:[YourProtocol class]];
Run Code Online (Sandbox Code Playgroud)