Как я могу надежно обнаружить щелчок по ссылке в UIWebView?

У меня есть UIWebView и мне нужно что-то сделать, когда пользователь нажимает на ссылку. Существует функция обратного вызова делегата, которую можно использовать для обнаружения отводов:

- (BOOL) webView: (UIWebView*) webView
    shouldStartLoadWithRequest: (NSURLRequest*) request
    navigationType: (UIWebViewNavigationType) navigationType
{
    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
        …
    }
}

Проблема в том, что этот код не обрабатывает все клики по ссылкам. Например, простая страница результатов поиска Google делает что-то странное со ссылками:

<a href="http://example.com/" class="l" onmousedown="return rwt(…)">
    <em>Link Text</em>
</a>

rwt функция приводит к тому, что ссылки не вызывают UIWebViewNavigationTypeLinkClicked событие, когда постучал. Есть ли способ надежно обнаружить все события, попадающие в корзину "перейти на другую страницу"?

4 ответа

Решение

До сих пор я пришел к следующему решению. Сначала я вставляю некоторый код JS на страницу при загрузке:

function reportBackToObjectiveC(string)
{
    var iframe = document.createElement("iframe");
    iframe.setAttribute("src", "callback://" + string);
    document.documentElement.appendChild(iframe);
    iframe.parentNode.removeChild(iframe);
    iframe = null;
}

var links = document.getElementsByTagName("a");
for (var i=0; i<links.length; i++) {
    links[i].addEventListener("click", function() {
        reportBackToObjectiveC("link-clicked");
    }, true);
}

Когда пользователь нажимает на ссылку, я знаю ее заранее благодаря webView:shouldStartLoadWithRequest: navigationType: вызов делегата:

if ([[[request URL] scheme] isEqualToString:@"callback"]) {
    [self setNavigationLeavingCurrentPage:YES];
    return NO;
}

Затем, если другой запрос приходит и _navigationLeavingCurrentPage это правда, я знаю, что пользователь нажал на ссылку, хотя флаг типа навигации UIWebViewNavigationTypeOther, Я все еще должен тщательно протестировать решение, так как боюсь, что оно приведет к ложным срабатываниям.

Вам необходимо добавить эту строку

webView.dataDetectorTypes = UIDataDetectorTypeAll;

затем

  • (BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType

метод получит вызов.

Я полагаю, что это можно сделать, внедрив в код HTML веб-сайта пользовательский JavaScript, который будет отслеживать события, и в зависимости от того, какое событие вы хотите отслеживать, он может вызвать перенаправление страницы с помощью пользовательской схемы URL, которую вы можете перехватить в mustStartLoadWithRequest.

Что-то вроде этого:

<script>
// Function to capture events
function captureEvent(el) {
  window.location.href="callback://"+el.href;  
}

var elms = document.getElementsByTagName("a"); 
for (var i=0; i<elms.length; i++) {
  elms[i].addEventListener("onmousedown", function(){captureEvent(el)}, true); 

 }
</script>

Затем в mustStartLoadWithRequest вы можете искать NSURLRequest, которые имеют схему callback:// url, и делать все, что захотите.

Это не было проверено, но что-то вроде этого может привести вас в правильном направлении.

Кроме того, так как это было упомянуто, да, вы можете добавить свой собственный скрипт на любую веб-страницу, используя это:

- (void)webViewDidFinishLoad:(UIWebView *)webView 
{
    [super webViewDidFinishLoad:webView];    
    [webView stringByEvaluatingJavaScriptFromString:@"document.body.insertAdjacentHTML('BeforeEnd','<script>....</script>');"];
}

У меня была куча проблем, чтобы заставить это работать. Использование UITapGestureRecognizer работает, за исключением того, что он всегда будет получать сигналы, даже для ссылок. К сожалению, ссылки имеют задержку около 300 мс, прежде чем они будут распознаны, что означает, что распознаватель жестов получает сигналы до того, как ссылка будет распознана, что создает проблему синхронизации (что еще хуже, потому что вам не нужно жестко кодировать время ожидания в случае Apple меняет это). Кроме того, ожидание касания более 300 мс дает плохой пользовательский интерфейс для моего приложения.

Так что я закончил тем, что наложил прозрачный div поверх всего, что получает не связанные ссылки. Затем разместите ссылки на более высоком уровне z. Наконец, убедитесь, что все использует ontouchend="javascript:window.location.href='...';", ontouchend будет действовать только на выпуске крана, чего ожидают пользователи. Настройка window.location.href загружает новую страницу, гарантируя, что все вызовы вызывают -webView:shouldStartLoadWithRequest:navigationType: и я могу проверить URL, чтобы увидеть, что мне нужно сделать.

HTML выглядит так:............

(Я не совсем уверен, что "position: родственник" всегда помещает вещи в то же положение, что и в противном случае, но это хорошо сработало для моей простой страницы; ваш пробег может отличаться. Однако вам понадобится положение: что-то, чтобы получить z-индекс для работы.)

Другие вопросы по тегам