UIWebView shouldStartLoadWithRequest срабатывает только один раз при вызове модального представления изнутри

У меня есть часть моего приложения, написанного на JS и работающего внутри WebView. Я использую метод UIWebView shouldStartLoadWithRequest для захвата HTTP-запросов как средства связи между JS и obj-c. Это отлично работает, пока я не попытаюсь загрузить контроллер модального представления через веб-просмотр изнутри метода shouldStartLoadWithRequest. Как только это произойдет, shouldStartLoadWithRequest больше не вызывается. Иногда мне нужно отклонить этот модальный контроллер представления и вернуться к веб-просмотру и сделать некоторые вещи, а затем повторно представить модальный контроллер. Модальный контроллер появляется в первый раз нормально, затем я отклоняю его и пытаюсь представить его снова, перейдя по URL-адресу из javascript, и он больше не будет отображаться. NSLogs внутри shouldStartLoadWithRequest никогда не запускаются.

В моем javascript я делаю что-то вроде этого:

 window.location='myapp:whateverMethod';

Целевой код c выглядит так:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *requestString = [[request URL] absoluteString];
    NSLog(@"REQUEST URL: %@", requestString);
    if([requestString hasPrefix:@"myapp:"]) {
        NSArray *components = [requestString componentsSeparatedByString:@":"];
        NSString *function = [components objectAtIndex:1];
        if([self respondsToSelector:NSSelectorFromString(function)]) {
            [self performSelector:NSSelectorFromString(function)];
        }
        return NO;
    }
    return YES;
}

-(void) whateverMethod {
    NSLog(@"whateverMethod called!");
    // This is a quick way to grab my view controller from the storyboard, so assume it exists
    UIViewController *splash = [self.storyboard instantiateViewControllerWithIdentifier:@"splashViewController"];
    [self presentModalViewController:splash animated:NO];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        [self dismissModalViewController:splash animated:NO];
    });
}

На данный момент мой веб-просмотр все еще виден. Я перехожу со страницы на страницу в своем веб-приложении, и весь javascript отлично работает в нем, но метод делегата «shouldStartLoadWithRequest» веб-просмотра больше не вызывается. Я не могу понять почему. У кого-нибудь есть идеи?


person Benjamin Oman    schedule 13.07.2013    source источник
comment
Не найдя решения, которое соответствует потребностям этого проекта, я закончил тем, что имитировал модальное представление внутри веб-представления с помощью анимации CSS и т.д. (достаточно близко к тому, как выглядит модальное представление), и, таким образом, мне больше не нужно было скрывать веб-представление.   -  person Benjamin Oman    schedule 07.03.2014


Ответы (4)


Я заметил, что Cordova не устанавливает свойство window.location. Вместо этого у него есть два варианта: он либо создает iframe и устанавливает src iframe для этого URL-адреса, либо создает объект XMLHttpRequest, например. в функции iOSExec ():

    if (bridgeMode) {
        execXhr = execXhr || new XMLHttpRequest();
        // Changeing this to a GET will make the XHR reach the URIProtocol on 4.2.
        // For some reason it still doesn't work though...
        execXhr.open('HEAD', "file:///!gap_exec", true);
        execXhr.setRequestHeader('vc', cordova.iOSVCAddr);
        if (shouldBundleCommandJson()) {
            execXhr.setRequestHeader('cmds', nativecomm());
        }
        execXhr.send(null);
    } else {
        execIframe = execIframe || createExecIframe();
        execIframe.src = "gap://ready";
    }

При этом может быть полезно использовать что-то вроде Cordova вместо того, чтобы пытаться катить его самостоятельно (даже если это просто встраивая свой контроллер представления), поскольку они справляются с множеством головных болей, которые возникают с делегатами веб-просмотра.

person mweiss    schedule 14.07.2013
comment
Интересный. Я действительно пробовал создавать запросы с помощью обоих этих методов и получил тот же результат (shouldStartLoading выполняется до тех пор, пока не появится модальное окно, а затем остановится). Было бы интересно попробовать это с кордовой и посмотреть, получится ли такой же результат. Это похоже на нюанс в iOS, но я могу ошибаться. - person Benjamin Oman; 17.07.2013

У меня была такая же проблема, но связанная с использованием привязки href = "#".

Этот ответ на переполнение стека отсортировал его

В этой ветке есть больше ответов, касающихся widow.location, так что, возможно, вам повезет с ними.

person Disobedient Media    schedule 07.08.2013

Проверил Кордову, и у них есть собственная система очередей, на самом деле не помощь. Но...

Ответ Disobedient Media подсказал мне идею. Почему бы не попробовать window.location.hash вместо window.location.

Теперь некоторый JS-код для ведения журнала:

function sendMsgToNative(msg)
{
    window.location.hash = '~cmd~' + msg;
}
console.log = function (msg) { sendMsgToNative('log~js ' + msg); };

а код Objective-C:

NSString *req = [request.URL absoluteString];
NSArray *components = [req componentsSeparatedByString:@"~"];

// Check for your protocol
if ([components count] > 1 && [(NSString *)[components objectAtIndex:1] isEqualToString:@"cmd"])
{
    // Look for specific actions
    if ([(NSString *)[components objectAtIndex:2] isEqualToString:@"log"])
    {
        NSString *logStr = [(NSString *)[components objectAtIndex:3] stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
        LOGI("%@", logStr);
    }
}

Вы получаете полный URL-адрес, включая http: ..., поэтому я выбрал тильду вместо двоеточия и увеличил индексы. Теперь вы можете волей-неволей регистрировать все и отправлять любое количество команд, которое хотите, и все они пройдут :-)

person Maitreya    schedule 22.11.2013

Я (смущенно) потратил пару часов на работу над этим сегодня и понял, что в моем viewDidDisappear: я устанавливал UIWebViewDelegate на ноль!

Все, что мне нужно было сделать, чтобы исправить, - это как только модальное окно было закрыто, повторно установило UIWebViewDelegate, и все снова заработало.

person jklp    schedule 19.09.2014