首页 > 解决方案 > Webview App 中的 Google 和 Facebook 登录 (OAuth)(需要覆盖弹出功能吗?)

问题描述

我正在使用 WebView 将我的响应式网站变成原生应用程序。几乎一切似乎都在工作,但我无法工作的一件事是我的“使用 Facebook 登录”和“使用 Google 登录”按钮。顺便说一句,谷歌一键登录工作正常(在 WebView 应用程序在不同的页面上登录到谷歌之后,即 Gmail),但“用 Facebook 登录”和“用谷歌登录”按钮不起作用。请注意,我实际上已经正确配置了我的意图(即,任何带有我的域名的 returnURL 或 callbackURL 都会被调用,仍然会通过应用程序调用),但我相信来自 Google 和 Facebook 的这些登录 API 不会返回用户到任何 returnURL,而只是将他们的结果传递回最初打开登录弹出窗口的 javascript。

问题如下(我认为):起初,两个按钮都在单独的浏览器窗口(Chrome)中打开了链接。当我完成登录过程(使用 Google 或 Facebook)时,此浏览器窗口会自动关闭,但没有任何内容返回到我的应用程序(因此,我的应用程序不知道用户完成了 OAuth 过程)。所以我决定设置 webSettings.setSupportMultipleWindows(false)。这至少解决了我的 Instagram API 问题(因为那也不起作用),并且它也确实使 Google 和 Facebook 身份验证窗口现在在应用程序中打开(所以我认为我更接近于得到这个工作),但问题是,OAuth 过程的返回数据/结果仍未返回到我的应用程序。事实上,Facebook 登录屏幕一旦完成就会完全关闭我的应用程序(我猜是窗口。close() 也会影响我的 WebView 应用程序,或者类似的东西)。另一方面,对于 Google,在登录后,页面保持白色。按返回确实可以让我返回到我的应用程序的登录屏幕。

以下是正在发生的事情的示例:

Facebook:

在此处输入图像描述

谷歌(第一次,登录过程有效,但完成登录后,我们最终得到如下相同的白页):

在此处输入图像描述

Google(之后每次登录 Google 后):

在此处输入图像描述

在我的应用程序的网站版本中处理响应的 javascript 一切正常!它从对 Google 或 Facebook 的 OAuth 调用捕获结果并处理返回的电子邮件地址和 Google/Facebook ID,然后将用户登录到我的应用程序。

我的问题可能与: Android Google login not working inside WebView

但我无法让它发挥作用。如果有人对这种 WebView 技术有更好的理解,或者知道如何将该主题中提到的解决方案应用于我的情况,我们将不胜感激!

我还阅读了:Google 登录无法正常工作的 android webview 应用程序

该主题中的几个人表示我必须覆盖弹出处理,但我不知道该怎么做......

这是我的 MainActivity 文件:

webView.setWebViewClient(new MyWebViewClient() {
    private Handler notificationHandler;

    public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
        callback.invoke(origin, true, false);
    }

    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String url) {
        if (Config.FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE) {
            loadLocal(INDEX_FILE);
        } else {
            webView.setVisibility(View.GONE);
            offlineLayout.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {

        //Basic Overriding part here (1/2)

        if (url.startsWith("mailto:")) {
            startActivity(new Intent(Intent.ACTION_SENDTO, Uri.parse(url)));
            return true;
        }
        if (url.startsWith("share:") || url.contains("api.whatsapp.com")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }
        if (url.startsWith("whatsapp:")) {
            Intent i = new Intent();
            i.setPackage("com.whatsapp");
            i.setAction(Intent.ACTION_SEND);
            i.setType("text/plain");
            startActivity(i);
            return true;
        }
        if (url.startsWith("geo:") || url.contains("maps:")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }
        if (url.startsWith("market:")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }
        if (url.startsWith("maps.app.goo.gl")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }
        if (url.contains("maps.google.com")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }
        if (url.startsWith("intent:")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }
        if (url.startsWith("tel:")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }
        if (url.startsWith("sms:")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }
        if (url.startsWith("play.google.com")) {
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(i);
            return true;
        }


        if (OPEN_SPECIAL_URLS_IN_NEW_TAB) {
            WebView.HitTestResult result = view.getHitTestResult();
            String data = result.getExtra();
            Log.i(TAG, " data :" + data);
            if ((data != null && data.endsWith("#")) || url.startsWith("newtab:")) {
                CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
                builder.setToolbarColor(getResources().getColor(R.color.colorPrimaryDark));
                CustomTabsIntent customTabsIntent = builder.build();
                String finalUrl = url;

                if (url.startsWith("newtab:")) {
                    finalUrl = url.substring(7);
                }

                customTabsIntent.launchUrl(MainActivity.this, Uri.parse(finalUrl));
                webView.stopLoading();
                return false;
            }
        }
        return super.shouldOverrideUrlLoading(view, url);
    }
});
webView.getSettings().setSupportMultipleWindows(false);


webView.setWebChromeClient(new MyWebChromeClient() {
    private Handler notificationHandler;


    @Override
    public void onCloseWindow(WebView window) {
        super.onCloseWindow(window);
        Log.i(TAG, "onCloseWindow url " + window.getUrl());
        Log.i(TAG, "onCloseWindow url " + window.getOriginalUrl());
    }

    @Override
    public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, Message resultMsg) {

        Bundle extras = getIntent().getExtras();
        String URL = null;
        if (extras != null) {
            URL = extras.getString("ONESIGNAL_URL");
        }
        if (URL != null && !URL.equalsIgnoreCase("")) {
            isNotificationURL = true;
            deepLinkingURL = URL;
        } else isNotificationURL = false;

        Log.i(TAG, " LOG24 " + deepLinkingURL);

        if (!OPEN_SPECIAL_URLS_IN_NEW_TAB) {
            Log.i(TAG, "if ");
            WebView.HitTestResult result = view.getHitTestResult();
            String data = result.getExtra();
            Context context = view.getContext();
            if (data == null) {
                Log.i(TAG, "else true ");
                WebView newWebView = new WebView(view.getContext());
                newWebView.setWebChromeClient(new MyWebChromeClient());
                WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
                transport.setWebView(newWebView);
                resultMsg.sendToTarget();
                return true;
            } else {
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(data));
                context.startActivity(browserIntent);
            }
        } else {
            CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
            builder.setToolbarColor(getResources().getColor(R.color.colorPrimaryDark));
            CustomTabsIntent customTabsIntent = builder.build();
            WebView.HitTestResult result = view.getHitTestResult();
            String data = result.getExtra();
            Log.i("TAG", " data " + data);
            String url = "";
            WebView newWebView = new WebView(view.getContext());
            newWebView.setWebChromeClient(new WebChromeClient());
            WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
            transport.setWebView(newWebView);
            resultMsg.sendToTarget();

        }
        Log.i("TAG", " running this main activity ");
        return true;
    }

    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
        Log.i(TAG, " onJsalert");
        return super.onJsAlert(view, url, message, result);
    }

    public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
        callback.invoke(origin, true, false);
    }

    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        mUM = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        startActivityForResult(Intent.createChooser(i, "Upload"), FCR);
    }

    @SuppressLint("InlinedApi")
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {

        if (Config.requireStorage && Config.requireCamera) {
            String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA};

            if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED
                    && ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, perms, FCR);

            } else if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, FCR);

            } else if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, FCR);
            } else if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECORD_AUDIO)
                    != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.RECORD_AUDIO}, FCR);
            }

            if (mUMA != null) {
                mUMA.onReceiveValue(null);
            }
            mUMA = filePathCallback;

            if (Arrays.asList(fileChooserParams.getAcceptTypes()).contains("audio/*")) {
                Intent chooserIntent = fileChooserParams.createIntent();
                startActivityForResult(chooserIntent, CODE_AUDIO_CHOOSER);
                return true;
            }

            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            if (takePictureIntent.resolveActivity(MainActivity.this.getPackageManager()) != null) {
                File photoFile = null;
                try {
                    photoFile = createImageFile();
                    takePictureIntent.putExtra("PhotoPath", mCM);
                } catch (IOException ex) {
                    Log.e(TAG, "Image file creation failed", ex);
                }
                if (photoFile != null) {
                    mCM = "file:" + photoFile.getAbsolutePath();
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                            FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".provider", photoFile));
                } else {
                    takePictureIntent = null;
                }
            }
            Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
            if (takeVideoIntent.resolveActivity(MainActivity.this.getPackageManager()) != null) {
                File videoFile = null;
                try {
                    videoFile = createVideoFile();
                    takeVideoIntent.putExtra("PhotoPath", mVM);
                } catch (IOException ex) {
                    Log.e(TAG, "Video file creation failed", ex);
                }
                if (videoFile != null) {
                    mVM = "file:" + videoFile.getAbsolutePath();
                    takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                            FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".provider", videoFile));
                } else {
                    takeVideoIntent = null;
                }
            }


            Intent contentSelectionIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
            contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
            contentSelectionIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/* video/*");
            contentSelectionIntent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/*", "video/*"});


            Intent[] intentArray;
            if (takePictureIntent != null && takeVideoIntent != null) {
                intentArray = new Intent[]{takePictureIntent, takeVideoIntent};
            } else if (takePictureIntent != null) {
                intentArray = new Intent[]{takePictureIntent};
            } else if (takeVideoIntent != null) {
                intentArray = new Intent[]{takeVideoIntent};
            } else {
                intentArray = new Intent[0];
            }

            Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
            chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
            chooserIntent.putExtra(Intent.EXTRA_TITLE, "Upload");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
            startActivityForResult(chooserIntent, FCR);
        }
        return true;
    }
});

final WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setGeolocationEnabled(true);
webSettings.setBuiltInZoomControls(false);
webSettings.setSupportZoom(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
if (Config.CLEAR_CACHE_ON_STARTUP) {
    webSettings.setAppCacheEnabled(false);
    webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
} else {
    webSettings.setAppCacheEnabled(true);
    webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
}
webSettings.setAllowUniversalAccessFromFileURLs(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowFileAccess(true);
//webSettings.setLoadWithOverviewMode(true);
webSettings.setUseWideViewPort(true);
webSettings.setAllowContentAccess(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);
webSettings.setDatabaseEnabled(true);
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

if (!Config.USER_AGENT.isEmpty()) {
    webSettings.setUserAgentString(Config.USER_AGENT);
}

请注意,上面代码中的 Config.VARIABLES 是在配置文件中定义的。我正在使用一个假的用户代理(一个不包含 wv- 或 webview- 的用户代理),正如许多其他人已经在这些主题中建议的那样(因为这会导致 Google 出现 UserAgent Not Allowed 错误)。此外,OPEN_SPECIAL_URLS_IN_NEW_TAB 设置为 true,正如您从 Facebook 演示中看到的那样,尽管 setSupportMultipleWindows() 已关闭,但该应用程序仍然可以在应用程序本身之上打开新标签(而不是打开外部浏览器窗口)。任何帮助将不胜感激!!

标签: androidwebviewoauthpopupgoogle-oauth

解决方案


Google 已阻止非本地 WebView 集成使用此线程中讨论的oAuth ,并且更改用户代理不再有效。您最好的选择是使用本机集成

Facebook 问题似乎与此线程中讨论的问题相似。


推荐阅读