2014-09-22 4 views
0

Новое в iOS 8 - это ошибка, которая блокирует пользовательский интерфейс, когда происходит более чем несколько JavaScript-сообщений.iOS 8 JavaScript для UIWebView ошибка связи

Связь с Javascript осуществляется через UIWebView's stringByEvaluatingJavaScriptFromString, а JavaScript для родного - через пользовательскую схему URL.

Если я делаю три или более сообщений, то первые два происходят немедленно, однако последующие принимают 10 секунд на сообщение.

Кто-нибудь испытывает это?

EDIT: 2014/09/23

В частности, проблема возникает, если вы делаете два JavaScript для родных вызовов последовательно,

[self.webView stringByEvaluatingJavaScriptFromString:@"calliOS('aurlscheme://awebview?say=two'); calliOS('aurlscheme://awebview?say=cat');"]; 

где calliOS() является функцией JavaScript, который использует для the iframe hack, чтобы вызвать собственный код через схему URL.

Если заменить IFrame взломать с прямым вызовом 'window.location',

[self.webView stringByEvaluatingJavaScriptFromString:@"window.location='aurlscheme://awebview?say=two';window.location='aurlscheme://awebview?say=cat';"];

Вы теряете все, кроме последнего запроса схемы URL.

Итак, в заключение, , делая быстрый последовательный JavaScript для родных вызовов, либо использовать IFrame хак и пользовательский интерфейс зависает на несколько секунд, или вы используете window.location путь и потерять все, кроме последнего запроса.

+0

Я также заинтересован в этом. Можете ли вы настроить собственные схемы URL-адресов на работу?До сих пор я не получал уведомления о них в webView: shouldStartLoadWithRequest: navigationType на iOS 8. – Alexander

+0

Да, это работает для меня, хотя я использую 'application: application handleOpenURL: url', чтобы поймать запрос, проанализировать строку запроса GET и передать словарь параметров в соответствующий контроллер представления. – paulvs

+0

@AlexanderCollins, см. Мой ответ ниже, он работает для меня в iOS 8. – paulvs

ответ

1

Это решение работает для меня.

Каждый раз, когда JavaScript отправляет запрос в машинный код, метод делегата,

- webView:shouldStartLoadWithRequest:navigationType: 

должен получить запрос перед тем JavaScript отправляет новый запрос, в противном случае мы сталкиваемся с разного рода ошибок. Итак, мы внедряем кеш в JavaScript для хранения ожидающих запросов и запускаем только новый, как только предыдущий запрос был получен.

Итак, решение:

JavaScript

// We need an array (cache) to hold the pending request URLs. 
var iOSRequestCache = []; 

/** 
Add a new iOS request to the cache. 
@params (Dictionary) - The query parameters to send to the native code. 
*/ 
function newiOSRequest(parameters) { 
    // Make the full request string. 
    var str = []; 
    for (var p in parameters) 
     if (parameters.hasOwnProperty(p)) { 
      str.push(encodeURIComponent(p) + "=" + encodeURIComponent(parameters[p])); 
     } 
    var queryString = str.join("&"); 

    var request = 'myurlscheme://webview?' + queryString; 

    // Add the new request to the cache. 
    iOSRequestCache.push(request); 

    console.log("Added new request: " + request); 

    // If this new request is the only one in the cache, fire it off to the native side. Else, do nothing. 
    if (iOSRequestCache.length == 1) { 
     console.log("Fired request: " + request); 
     window.location = iOSRequestCache[0]; 
    } 
} 

/** 
Called by the native side to notify that a request was processed and to procced with the next pending request, if any. 
*/ 
function resolveiOSRequest(request) { 
    console.log("Resolving request: " + request); 
    // Search for the processed request in the cache and delete it. 
    var requestIndex = iOSRequestCache.indexOf(request); 
    if (requestIndex != -1) { 
     iOSRequestCache.splice(requestIndex, 1); // Remove the request from the array. 
    } 
    console.log("Deleting resolving request: " + request); 

    if (iOSRequestCache.length >= 1) { 
     console.log("Firing next request: " + request); 
     window.location = iOSRequestCache[0]; 
    } 

    console.log("Resolved request: " + request); 
} 

Objective-C (машинный код)

/* 
Called whenever a URL is requested inside the web view. 
*/ 
- (BOOL)webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType 
{ 
    // The URL Scheme we use for web view <-> native communication (we grab it from the .plist file of the project target.) 
    NSString *URLScheme = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"][0][@"CFBundleURLSchemes"][0]; 

    // If we get a request from this URL scheme, we grab the parameters and take the appropriate action. 
    if ([inRequest.URL.scheme isEqualToString:URLScheme]) { 
     // Get the query parameters. 
     NSMutableDictionary *params = [NSMutableDictionary dictionary]; 
     NSArray *pairs = [inRequest.URL.query componentsSeparatedByString:@"&"]; 
     for (NSString *pair in pairs) 
     { 
      NSArray *elements = [pair componentsSeparatedByString:@"="]; 
      NSString *key = elements[0]; 
      NSString *value = elements[1]; 
      key = [key stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 
      value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 
      [params setObject:value forKey:key]; 
     } 

     // Here we notify the JavaScript that we received this communication so that the next one can be sent. 
     NSString *javaScript = [NSString stringWithFormat:@"resolveiOSRequest('%@')", inRequest.URL.absoluteString]; 
     [self.webView stringByEvaluatingJavaScriptFromString:javaScript]; 

     // Call the method that handles our JavaScript to native requests. 
     // HERE WE TAKE WHATEVER ACTION WE WANT WITH THE DICTIONARY THAT 
     // THE JAVASCRIPT SENT US. 
     [self handleWebViewMessage:params]; 
    } 

    return YES; 

} 

Использование:

newiOSRequest({ 
    animal    : "cat", 
    favfood    : "gocat", 
}); 
Смежные вопросы