【问题标题】:InAppBrowser OAUTH didFailLoadWithError 1004 "Could not connect to the server." "<allow-navigation> not set for url"InAppBrowser OAUTH didFailLoadWithError 1004 “无法连接到服务器。” “<allow-navigation> 未设置为 url”
【发布时间】:2016-10-17 04:44:06
【问题描述】:

我看到这个问题与另一个问题 (webView:didFailLoadWithError -1004: Could not connect to the server while connecting google plus in Phonegap ios) 相似,但在某种程度上有所不同,因为我已经逐行检查了代码并且它正在做同样的事情,但它仍然不适合我.也可能是因为我使用不同的版本:iPhone 5S 上的 iOS 9.3.2)、Cordova 6.1.1 和 cordova-plugin-inappbrowser 1.3.0。

我的代码在我的 Android 上运行良好,但在 iPhone 上却不行。代码如下:

    var googleapi = {
    authorize: function(options) {
        var deferred = $.Deferred();
        var authUrl = GOOGLE_CLIENT_API_URL + $.param({
            client_id: options.client_id,
            redirect_uri: options.redirect_uri,
            response_type: 'code',
            scope: options.scope
        });
        console.log("authUrl: " + authUrl);
        var authWindow = window.open(authUrl, "_blank", "location=no,toolbar=no");  // for iOS add 'toolbar=no'

        //The recommendation is to use the redirect_uri "urn:ietf:wg:oauth:2.0:oob" 
        //which sets the authorization code in the browser's title. However, we can't 
        //access the title of the InAppBrowser. 
        // 
        //Instead, we pass a bogus redirect_uri of "http://localhost", which means the 
        //authorization code will get set in the url. We can access the url in the 
        //loadstart and loadstop events. So if we bind the loadstart event, we can 
        //find the authorization code and close the InAppBrowser after the user 
        //has granted us access to their data. 
        //
        // To clear the authorization, go to https://accounts.google.com/IssuedAuthSubTokens.
        $(authWindow).on('loadstart', function(e) {
            var url = e.originalEvent.url;
            var code = /\?code=(.+)$/.exec(url);
            var error = /\?error=(.+)$/.exec(url);

            if(code || error) {
                authWindow.close();
            }
            if (code) { 
                //Exchange the authorization code for an access token 
                $.post('https://accounts.google.com/o/oauth2/token', { 
                    code: code[1], 
                    client_id: options.client_id, 
                    client_secret: options.client_secret, 
                    redirect_uri: options.redirect_uri, 
                    grant_type: 'authorization_code' 
                }).done(function(data) {
                    // use the token we got back from oauth to setup the api.
                    gapi.auth.setToken(data);
                    // load the drive api.
                    loadDriveApi();
                    deferred.resolve(data); 
                }).fail(function(response) {
                    console.log("Posting code to Google failed.  No OAuth token will be returned.");
                    deferred.reject(response.responseJSON); 
                }); 
            } else if (error) { 
                //The user denied access to the app 
                console.log("Error retrieving code from Google.");
                deferred.reject({ 
                    error: error[1] 
                }); 
            } 
        });

        return deferred.promise();
    }
};

function checkAuth() {
    if(device.platform === 'browser') {
        console.log("calling gapi.auth.authorize()");
        gapi.auth.authorize(
        {
            'client_id' : CLIENT_ID,
            'scope' : SCOPES.join(' '),
            'immediate' : true
        }, handleAuthResult);
    } else {
        // because this is called only after deviceready(), InAppBrowser is initialized by now:
        console.log("using the InAppBrowser plugin to authenticate.");
        window.open = cordova.InAppBrowser.open;

        googleapi.authorize(
        {
            'client_id' : CLIENT_ID,
            'client_secret' : CLIENT_SECRET,
            'redirect_uri' : REDIRECT_URI,
            'scope' : SCOPES.join(' ')
        }, handleAuthResult);
    }
}

/**
 * Handle response from authorization server.
 *
 * @param {Object} authResult Authorization result.
 */
function handleAuthResult(authResult) {
    var authMenuItem = document.getElementById("menuitemenablegoogledrivebackup");
    if (authResult && !authResult.error) {
        // If already authorized, change menu option to allow user to deny Authorization
        authMenuItem.innerHTML = l("Disable Google Drive Backup");
        loadDriveApi();
    } else {
        alert("Authorization Error: " + authResult.error);
        console.log("inside handleAuthResult, authResult.error: " + authResult.error);

        // Show auth menu item, allowing the user to initiate authorization
        authMenuItem.innerHTML = l("Enable Google Drive Backup");
        // use the InAppBrowser to display the authorization window:
        // var authWindow = window.open(authUrl, '_blank', 'location=no,toolbar=no');
        // or?
        // gapi.auth.authorize(
        //  {
        //      client_id: CLIENT_ID,
        //      scope: SCOPES.join(' '),
        //      immediate: false
        //  }, handleAuthResult)
    }
}

/**
 * Load Drive API client library.
 */
function loadDriveApi() {
    try {
    gapi.client.load('drive', 'v2', null).then(function(resp) {
        console.log("Google Drive API v2 loaded successfully.");
    }, function(reason) {
        alert('Google Drive API v2 FAILED to load: ' + reason.result.error.message);
        console.log('Google Drive aPI v2 FAILED to load: ' + reason.result.error.message);
    });
    } catch(err) {
        alert(err.message);
        console.log("Google Drive API v2 FAILED to load.  Exception: " + err.message);
    }
}

通过调试,我看到Android版本调用window.open()调用,首先通过loadstart处理程序一次,使用原始URL,但是它没有包含代码,也没有错误,所以它只是通过.然后 redirect_url 在第二次调用 loadstart 处理程序时出现(这是由 InAppBrowser 执行的吗?)但这次它有更短的 redirect_url 并附加了代码,因此代码随后成功用于获取“$”上的令牌.post”调用。但是,在 iOS 上,没有第二次调用 loadstart 处理程序。

当我在 Chrome 调试器中运行它时,我没有收到任何错误,只是静默失败。在 XCode 调试器中,我收到如下错误:

2016-06-09 20:47:27.014 APass2[675:398271] 设置 WebView 的框架 到 {{0, 0}, {320, 524}} 2016-06-09 20:47:27.015 APass2[675:398271] 将 WebView 的框架设置为 {{0, 0}, {320, 568}} 2016-06-09 20:47:27.026 APass2 [675:398271] 线程警告:['InAppBrowser'] 占用 '39.259033' 毫秒。插件应该使用后台线程。 2016-06-09 20:47:27.749 APass2[675:398271] webView:didFailLoadWithError - -1004: 无法连接到服务器。 2016-06-09 20:47:28.955 APass2[675:398271] 错误内部导航被拒绝 - 未设置 url='https://content.googleapis.com/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.joG9nQvYxYQ.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCPyXDgCg_S7GlvvvMpztuAZ6V0pEA#parent=file%3A%2F%2F&rpctoken=1268129019'

没有调用我的成功或失败回调。

请帮忙!!!我现在完全不知所措了。

谢谢, 爱德华

【问题讨论】:

    标签: ios cordova oauth google-oauth inappbrowser


    【解决方案1】:

    首先,通过查看 InAppBrowser 文档,我了解到还有一个“loaderror”事件。仅在 iOS 上,对 inAppBrowser.open() 的调用会导致调用“loaderror”处理程序。在“loaderror”处理程序中,我还能够获取 url,就像原始代码在“loadstart”上所做的一样。在 Chrome 和 Safari 中同时调试我能够看到“loaderror”中的 url 与“loadstart”处理程序中的 url 完全相同,并且解析代码和错误的方式完全相同。所以,在第一次剪辑中,我以这种方式破解它并进入下一个阶段(成功 - 有点)。然后我遇到了另一个与&lt;access-navigation&gt; 相关的错误。谷歌搜索了更多,我发现在项目根目录的 config.xml 中有一个可用的配置设置。

    更多谷歌搜索指向我说使用&lt;allow-navigation href="*" /&gt;的人

    显然,我对如此广泛的安全漏洞感到不满。

    所以,底线是我需要将 Google api 需要访问的 url 添加到 config.xml 文件中,如下所示:

    <allow-navigation href="https://accounts.google.com/*" />
    <allow-navigation href="https://content.googleapis.com/*" />
    

    我仍然需要清理代码,并且可能会简化“loaderror”处理程序中的错误处理,但我现在已经开始工作了!

    最令人沮丧的是,这个设置在 Android 上根本不需要,所以我没有理由怀疑这是问题所在。

    感谢那些花时间看这个的人!

    爱德华

    【讨论】:

      猜你喜欢
      • 2018-07-26
      • 1970-01-01
      • 2017-02-06
      • 2017-07-22
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      相关资源
      最近更新 更多