6

I've come across a fairly serious issue which relates to Mobile SDK 3.x - While it was good to move to Cordova 3.7, it introduces a rather unwanted bug which is also mentioned on other Stackoverflow posts such as this one

Essentially, the phone dialer returns an error while making a tel: URI call. When the dailer returns control back to my hybrid app - either pressing the Cancel button or after the call has ended, it leads to an error in both scenarios.

The workarounds mentioned on other threads related to whitelisting did not work for me.

6

For those facing the same issue, we managed to work around it with this approach

In Platform/ios/CordovaLib/Classes/CDWebViewDelegate.m, there is a method (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest with the following definition

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
    BOOL shouldLoad = YES;

    if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
        shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
    }

    VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, state, loadCount, request.URL);

    if (shouldLoad) {
        // When devtools refresh occurs, it blindly uses the same request object. If a history.replaceState() has occured, then
        // mainDocumentURL != URL even though it's a top-level navigation.
        BOOL isDevToolsRefresh = (request == webView.request);
        BOOL isTopLevelNavigation = isDevToolsRefresh || [request.URL isEqual:[request mainDocumentURL]];
        if (isTopLevelNavigation) {
            // Ignore hash changes that don't navigate to a different page.
            // webView.request does actually update when history.replaceState() gets called.
            if ([self request:request isEqualToRequestAfterStrippingFragments:webView.request]) {
                NSString* prevURL = [self evalForCurrentURL:webView];
                if ([prevURL isEqualToString:[request.URL absoluteString]]) {
                    VerboseLog(@"Page reload detected.");
                } else {
                    VerboseLog(@"Detected hash change shouldLoad");
                    return shouldLoad;
                }
            }

            switch (_state) {
                case STATE_WAITING_FOR_LOAD_FINISH:
                    // Redirect case.
                    // We expect loadCount == 1.
                    if (_loadCount != 1) {
                        NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%ld", (long)_loadCount);
                    }
                    break;

                case STATE_IDLE:
                case STATE_IOS5_POLLING_FOR_LOAD_START:
                case STATE_CANCELLED:
                    // Page navigation start.
                    _loadCount = 0;
                    _state = STATE_WAITING_FOR_LOAD_START;
                    break;

                default:
                    {
                        _loadCount = 0;
                        _state = STATE_WAITING_FOR_LOAD_START;
                        NSString* description = [NSString stringWithFormat:@"CDVWebViewDelegate: Navigation started when state=%ld", (long)_state];
                        NSLog(@"%@", description);
                        //Code changed to make tel link working. 
                        /* if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
                            NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description};
                            NSError* error = [[NSError alloc] initWithDomain:@"CDVWebViewDelegate" code:1 userInfo:errorDictionary];
                            [_delegate webView:webView didFailLoadWithError:error];
                        } */
                    }
            }
        } else {
            // Deny invalid URLs so that we don't get the case where we go straight from
            // webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount).
            shouldLoad = shouldLoad && [self shouldLoadRequest:request];
        }
        VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, state, loadCount);
    }
    return shouldLoad;
}

After scratching around for days (and nights), we figured out that it was this call to selector which was causing this issue and if we comment it out, it works without any issues.

 /* if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
                                NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description};
                                NSError* error = [[NSError alloc] initWithDomain:@"CDVWebViewDelegate" code:1 userInfo:errorDictionary];
                                [_delegate webView:webView didFailLoadWithError:error];
                            } */
  • This is great, thanks. Note also solves for when returning from other apps (e.g. SF1) too. This is the error that was being shown in xcode. [286:12052] CDVWebViewDelegate: Navigation started when state=1 [286:12052] ERROR|SFHybridViewController|Error while attempting to load web page: Error Domain=CDVWebViewDelegate Code=1 "CDVWebViewDelegate: Navigation started when state=1" UserInfo={NSLocalizedDescription=CDVWebViewDelegate: Navigation started when state=1} [286:12052] Failed to load webpage with error: CDVWebViewDelegate: Navigation started when state=1 – Todd Halfpenny Mar 25 '16 at 11:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.