UIWebViewDelegate ne surveille pas XMLHttpRequest?

est-il vrai que L'UIWebViewDelegate ne surveille pas les requêtes faites en utilisant une XMLHttpRequest? Si oui, est-il un moyen de surveiller ce genre de demandes?

p.ex. UIWebViewDelegate ne comprend pas cela dans -(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();
50
demandé sur Thys 2011-03-18 17:18:51

5 réponses

question intéressante.

il y a deux parties pour que cela fonctionne: un gestionnaire JavaScript et les méthodes de délégation UIWebView. Dans JavaScript, nous pouvons modifier des méthodes prototypes pour déclencher des événements lorsqu'une requête AJAX est créée. Avec notre Délégué UIWebView, nous pouvons capturer ces événements.

JavaScript Gestionnaire

nous devons être informés lorsqu'une demande AJAX est faite. J'ai trouvé la solution ici .

dans notre cas, pour faire fonctionner le code, j'ai mis le JavaScript suivant dans une ressource appelée ajax_handler.js qui est fourni avec mon application.

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();
}

ce que cela va réellement faire est de changer l'emplacement du navigateur à un schéma D'URL inventé (dans ce cas, mpAjaxHandle ) avec des informations sur la demande faite. Ne vous inquiétez pas, notre délégué à l'intercepter et de le le Lieu ne changera pas.

UIWebView Delegate

tout d'abord, nous devons lire notre fichier JavaScript. Je suggère de le stocker dans une variable statique. J'ai l'habitude d'utiliser + initialize.

static NSString *JSHandler;

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

ensuite, nous voulons injecter ce JavaScript avant qu'une page ne soit chargée pour que nous puissions recevoir tous les événements.

- (void)webViewDidStartLoad:(UIWebView *)webView {
    [webView stringByEvaluatingJavaScriptFromString:JSHandler];
}

Enfin, nous voulons capturer l'événement.

puisque le schéma D'URL est composé, nous ne voulons pas vraiment le suivre. Nous retournons Non et tout va bien.

#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;
}

j'ai créé un projet type avec la solution mais je n'ai nulle part où l'héberger. Vous pouvez moi un message si vous pouvez l'héberger et je vais éditer ce post en conséquence.

78
répondu Mike Pulaski 2017-05-23 10:30:49

vous pouvez utiliser un Nslprotocol. Par exemple, si vous appelez XMLHttpRequest avec http://localhost/path vous pouvez le gérer avec ce qui suit:

@interface YourProtocol: NSURLProtocol

puis pour la mise en œuvre:

+ (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
{
}

vous devez enregistrer le protocole comme suit:

    [NSURLProtocol registerClass:[YourProtocol class]];
19
répondu George 2012-07-24 04:56:22

en implémentant et en enregistrant une sous-classe de Neurlprotocol vous pouvez capturer toute la requête à partir de votre UIWebView. Il est peut-être exagéré, dans certains cas, mais si vous n'êtes pas en mesure de modifier le javascript effectivement en cours d'exécution est votre meilleur pari.

dans mon cas, je dois capturer toutes les requêtes et insérer un en-tête HTTP spécifique à chacune d'elles. J'ai fait cela en implémentant Nslprotocol, en l'enregistrant en utilisant registerClass et en répondant oui dans ma sous-classe à + (BOOL)peutinitwithrequest: (NSURLRequest *)request si la requête correspond aux URLs qui m'intéressent. Vous devez alors implémenter les autres méthodes du protocole. ceci peut être fait en utilisant une connexion Nslconnection, en définissant la classe de protocole comme délégué et en redirigeant les méthodes de délégation de Nslconnection vers Nslprotocolclient

3
répondu terrinecold 2012-01-31 11:17:41

il semble que c'est vrai. Il n'y a aucun moyen de surveiller ce que fait UIWebView au-delà de ce que fournit UIWebViewDelegate, à moins que vous ne puissiez trouver un moyen d'utiliser stringByEvaluatingJavaScriptFromString: pour injecter du Javascript pour faire ce dont vous avez besoin.

1
répondu Anomie 2011-04-14 18:59:35

comme d'autres peuples l'ont mentionné, UIWebViewDelegate observe des changements de fenêtre.localisation et iframe.src seulement.

dans le cas où vous voulez juste utiliser le schéma d'url personnalisé de iOS seulement, vous pouvez profiter de <iframe> comme ceci.

par exemple, si vous voulez appeler un schéma D'URL comme celui-ci

objc://my_action?arg1=1&arg2=2

dans votre fichier 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});
0
répondu Soyoes 2016-02-26 10:40:33