使 facebook 登录与 Android Webview 一起工作
Posted
技术标签:
【中文标题】使 facebook 登录与 Android Webview 一起工作【英文标题】:Making facebook login work with an Android Webview 【发布时间】:2012-09-20 19:35:13 【问题描述】:我只是想在 android 的 WebView 上实现 facebook 登录。问题是在我单击 html 页面上的 facebook 按钮并在 Facebook 对话框中插入用户名和密码之后。 url 重定向只是给我一个黑页。
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
WebView webview = new WebView(this);
webview.setWebChromeClient(new WebChromeClient());
webview.getSettings().setPluginState(PluginState.ON);
webview.getSettings().setjavascriptEnabled(true);
webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webview.setWebViewClient(new WebViewClient());
webview.loadUrl("http://peoplehunt.crowdscanner.com/hunt");
setContentView(webview);
这是我的 HTML 页面上的 Facebook 常规 javascript API,当点击 facebook 按钮时会调用此函数。
$("#login_facebook").click(function()
FB.login(function(response)
//This function should be called
if (response.authResponse)
FB.api('/me?fields=name,email,picture,id&type=large', function(response)
//console.log("email "+response.email);
$("#submitHandle").hide();
$("#loader").show();
//console.log('Good to see you, ' + response.picture + '.');
var theUsername = response.name;
theUsername = theUsername.replace(/ /g, '_')+"_"+response.id+"@meetforeal.com";
//console.log(theUsername);
$("input[name=email]").val(encodeURIComponent(response.email));
$("input[name=lastName]").val(encodeURIComponent(response.name));
$("input[name=avatarImage]").val(response.picture);
$("input[name=userName]").val(encodeURIComponent(theUsername));
$("#msg_twitter").fadeIn("slow");
$("#submitHandle").show();
$("#loader").hide();
$("#user").attr("action","/crowdmodule/auth/registerattendeefacebook");
$("#user").submit();
);
else
//console.log('User cancelled login or did not fully authorize.');
, scope: 'email');
关于如何在 Facebook 对话页面上重定向后获取响应的任何想法?谢谢。
【问题讨论】:
【参考方案1】:此代码对我有用!我的页面上有一个 LIKE、SHARE、Comments 按钮。
private lateinit var myWebView: WebView;
private val target_url = "https://www.webkomph.com"
private val target_url_prefix = "webkomph.com"
private var mContext: Context? = null
private var mWebviewPop: WebView? = null
private var mContainer: ConstraintLayout? = null
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
val cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true)
myWebView = findViewById(R.id.webkom_site);
mContainer = findViewById(R.id.webview_frame);
val webkomBlue = Color.parseColor("#1c71bc")
myWebView.setBackgroundColor(webkomBlue);
myWebView.background
val webSettings = myWebView.settings;
webSettings.setJavaScriptEnabled(true);
webSettings.setAppCacheEnabled(true);
webSettings.javaScriptCanOpenWindowsAutomatically = true;
webSettings.setSupportMultipleWindows(true)
myWebView.setWebViewClient(UriWebViewClient())
myWebView.setWebChromeClient(UriChromeClient())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
cookieManager.setAcceptThirdPartyCookies(myWebView, true)
myWebView.loadUrl(target_url);
mContext = this.applicationContext
override fun onBackPressed()
if (myWebView.canGoBack())
myWebView.goBack()
else
super.onBackPressed()
inner class UriWebViewClient : WebViewClient()
override fun shouldOverrideUrlLoading(
view: WebView,
url: String
): Boolean
val host = Uri.parse(url).host
//Log.d("shouldOverrideUrlLoading", url);
if(host == null || host == target_url_prefix)
// This is my web site, so do not override; let my WebView load
// the page
if (mWebviewPop != null)
mWebviewPop!!.setVisibility(View.GONE)
mContainer?.removeView(mWebviewPop)
mWebviewPop = null
return false
if (host == "m.facebook.com" || host == "www.facebook.com" || url.contains("ret=login"))
return false
// Otherwise, the link is not for a page on my site, so launch
// another Activity that handles URLs
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
return true
override fun onPageFinished(view: WebView?, url: String)
// Facebook redirects to this url once a user has logged in, this is a blank page so we override this
// http://www.facebook.com/connect/connect_to_external_page_widget_loggedin.php?............
if (url.contains("plugins/close_popup.php?reload") || url.contains("dialog/close_window") || url.contains("facebook.com/dialog/plugin.optin?"))
if(mWebviewPop != null)
mWebviewPop!!.visibility = View.GONE
mContainer!!.removeView(mWebviewPop)
mWebviewPop = null
if(myWebView != null && (url.contains("dialog/close_window") || url.contains("facebook.com/dialog/plugin.optin?")))
myWebView?.reload();
return
super.onPageFinished(view, url)
override fun onReceivedSslError(
view: WebView, handler: SslErrorHandler,
error: SslError
)
Log.d("onReceivedSslError", "onReceivedSslError")
//super.onReceivedSslError(view, handler, error);
inner class UriChromeClient : WebChromeClient()
override fun onCreateWindow(
view: WebView, isDialog: Boolean,
isUserGesture: Boolean, resultMsg: Message
): Boolean
mWebviewPop = WebView(mContext)
mWebviewPop!!.setVerticalScrollBarEnabled(false)
mWebviewPop!!.setHorizontalScrollBarEnabled(false)
mWebviewPop!!.setWebViewClient(UriWebViewClient())
mWebviewPop!!.getSettings().setJavaScriptEnabled(true)
mWebviewPop!!.getSettings().setSavePassword(false)
mWebviewPop!!.layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
mContainer?.addView(mWebviewPop)
val transport = resultMsg.obj as WebViewTransport
transport.webView = mWebviewPop
resultMsg.sendToTarget()
return true
override fun onCloseWindow(window: WebView)
Log.d("onCloseWindow", "called")
【讨论】:
【参考方案2】:这是一个示例 Android 项目: Github: Android_Popup_Webview_handler_example
这是一个 Android Studio 项目,展示了如何在 Android Webview 中处理弹出窗口。 大多数开源浏览器不支持打开弹出窗口。
弹出窗口在许多网站使用的 OAuth 登录中尤其重要(例如,www.feedly.com)。 此项目中的弹出窗口在对话框中打开,可以通过关闭按钮或按 Back 或如果弹出窗口自行关闭(就像大多数登录身份验证流程中发生的情况一样)关闭。
【讨论】:
Facebook 登录在这种情况下有效。谷歌登录不允许用户代理问题。 @vivek Sinha 这与另一个问题有关。从 2017 年 4 月起,Google 停止支持从 webview 登录。【参考方案3】:可能不是一个总是可行的答案,但另一个选择是从“弹出然后 JS”样式 OAuth 登录切换到非弹出“redirect_uri”OAUth 样式,将它们发送到登录页面,然后在成功/失败之后它们被发送到完成身份验证的“某些 uri err other”(例如:您自己网站上的另一个页面)。 FWIW。
FWIW facebook 说“如果你正在做 WebView 将它们重定向到https://www.facebook.com/connect/login_success.html”我的直觉是(只有一个 WebView 和)使用 OAuth 登录的情况,所以他们会添加一些身份验证然后您可以收集到 login_success.html 的参数,而不是正常的网络流程...
另一种可能性可能是 override javascript postMessage
函数,这样您就可以捕获 即将返回父窗口的内容。
【讨论】:
【参考方案4】:我在我的 android 应用程序上遇到了同样的问题。 问题的原因是 FB 登录 javascript 在新窗口中打开新页面。然后它会在登录成功后尝试关闭它并发送一些 javascript 身份验证代码。 WebView 通常是“仅单个窗口”,因此它没有地方可以返回,因此是空白屏幕。
请按照我的工作代码中的流动示例。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:background="#0099cc"
tools:context=".MyActivity"
android:id="@+id/webview_frame">
<WebView
android:id="@+id/webview"
android:layout_
android:layout_
/>
ID 为“webview”的 Webview 是我的内容的主视图。 以下是我的活动代码。
public class MyActivity extends Activity
/* URL saved to be loaded after fb login */
private static final String target_url="http://www.example.com";
private static final String target_url_prefix="www.example.com";
private Context mContext;
private WebView mWebview;
private WebView mWebviewPop;
private FrameLayout mContainer;
private long mLastBackPressTime = 0;
private Toast mToast;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_urimalo);
// final View controlsView =
// findViewById(R.id.fullscreen_content_controls);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
mWebview = (WebView) findViewById(R.id.webview);
//mWebviewPop = (WebView) findViewById(R.id.webviewPop);
mContainer = (FrameLayout) findViewById(R.id.webview_frame);
WebSettings webSettings = mWebview.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAppCacheEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setSupportMultipleWindows(true);
mWebview.setWebViewClient(new UriWebViewClient());
mWebview.setWebChromeClient(new UriChromeClient());
mWebview.loadUrl(target_url);
mContext=this.getApplicationContext();
private class UriWebViewClient extends WebViewClient
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
String host = Uri.parse(url).getHost();
//Log.d("shouldOverrideUrlLoading", url);
if (host.equals(target_url_prefix))
// This is my web site, so do not override; let my WebView load
// the page
if(mWebviewPop!=null)
mWebviewPop.setVisibility(View.GONE);
mContainer.removeView(mWebviewPop);
mWebviewPop=null;
return false;
if(host.equals("m.facebook.com"))
return false;
// Otherwise, the link is not for a page on my site, so launch
// another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error)
Log.d("onReceivedSslError", "onReceivedSslError");
//super.onReceivedSslError(view, handler, error);
class UriChromeClient extends WebChromeClient
@Override
public boolean onCreateWindow(WebView view, boolean isDialog,
boolean isUserGesture, Message resultMsg)
mWebviewPop = new WebView(mContext);
mWebviewPop.setVerticalScrollBarEnabled(false);
mWebviewPop.setHorizontalScrollBarEnabled(false);
mWebviewPop.setWebViewClient(new UriWebViewClient());
mWebviewPop.getSettings().setJavaScriptEnabled(true);
mWebviewPop.getSettings().setSavePassword(false);
mWebviewPop.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
mContainer.addView(mWebviewPop);
WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
transport.setWebView(mWebviewPop);
resultMsg.sendToTarget();
return true;
@Override
public void onCloseWindow(WebView window)
Log.d("onCloseWindow", "called");
这个问题的关键是onCreateWindow。一个新窗口被创建并插入到框架布局中,并在成功时删除。我在 shouldOverrideUrlLoading 添加了删除。
【讨论】:
if
条件应为 host.equals("m.facebook.com") || host.equals("www.facebook.com")
以匹配在重定向到移动版本之前首先加载 www 的情况。
我尝试了同样的方法,但我仍然得到空白页,有什么解决办法吗?
当使用任何包含target="_blank"
的链接时,这给我带来了问题 - mContainer 在某些情况下为空会触发空指针异常。为了解决这个问题,我只需要将以下行:mContainer.addView(mWebviewPop);
替换为:if (mContainer != null) mContainer.addView(mWebviewPop);
我还没有在旧的 Android 设备上测试过,但是在 API 21+ 上你需要添加:if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) cookieManager.getInstance().setAcceptThirdPartyCookies(myWebView, true);
我遵循了这段代码。但没有运气。出现FB登录页面。输入凭据并点击登录后,它卡在那里。【参考方案5】:
我的回答与这里的其他人基本相似,因为我创建了第二个WebView
来托管 Facebook 登录页面,而不是尝试通过重定向来解决问题。但是,我选择将登录WebView
放在它自己的Fragment
中,并给它自己专用的WebViewClient
和WebChromeClient
子类。我认为这样可以更轻松地了解每个组件所扮演的角色,以及哪些对象需要哪些设置和行为。
我还使用WebChromeClient.onCloseWindow()
来检测 Facebook 的 JavaScript 何时想要关闭登录窗口。从不同的答案来看,这比我最初采用的方法要强大得多。
在您的Activity
布局中,您将拥有托管 cmets 的“主要”WebView
,以及用于FacebookWebLoginFragment
的容器。登录 Fragment
在需要时即时创建,然后在 Facebook 的登录 JavaScript 请求关闭其窗口时删除。
我的Activity
布局如下所示:
<include layout="@layout/toolbar_common" />
<FrameLayout
android:id="@+id/main_layout"
android:layout_
android:layout_>
<FrameLayout
android:id="@+id/web_view_fragment_container"
android:layout_
android:layout_
android:overScrollMode="never"
/>
<!-- Used for Facebook login associated with comments -->
<FrameLayout
android:id="@+id/facebook_web_login_fragment_container"
android:layout_
android:layout_
android:overScrollMode="never"
android:visibility="gone"
/>
</FrameLayout>
在您的Activity
中,您需要代码来显示和隐藏 Facebook 网络登录片段。我使用 Otto 事件总线,所以我有如下事件处理程序。 (这里没有具体针对这个问题;我包含此代码只是为了让您了解登录 Fragment
如何适合整体结构。)
@Subscribe
public void onShowFacebookWebLoginEvent(ShowFacebookWebLoginEvent event)
FacebookWebLoginFragment existingFragment = getFacebookWebLoginFragment();
if (existingFragment == null)
mFacebookWebLoginFragmentContainer.setVisibility(View.VISIBLE);
createFacebookWebLoginFragment(event);
@Subscribe
public void onHideFacebookWebLoginEvent(HideFacebookWebLoginEvent event)
FacebookWebLoginFragment existingFragment = getFacebookWebLoginFragment();
if (existingFragment != null)
mFacebookWebLoginFragmentContainer.setVisibility(View.GONE);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.remove(existingFragment)
.commit();
@Nullable
private FacebookWebLoginFragment getFacebookWebLoginFragment()
FragmentManager fm = getSupportFragmentManager();
return (FacebookWebLoginFragment) fm.findFragmentById(R.id.facebook_web_login_fragment_container);
private void createFacebookWebLoginFragment(ShowFacebookWebLoginEvent event)
FragmentManager fm = getSupportFragmentManager();
FacebookWebLoginFragment fragment = (FacebookWebLoginFragment) fm.findFragmentById(R.id.facebook_web_login_fragment_container);
if (fragment == null)
fragment = FacebookWebLoginFragment.newInstance(event.getOnCreateWindowResultMessage());
fm.beginTransaction()
.add(R.id.facebook_web_login_fragment_container, fragment)
.commit();
当FacebookWebLoginFragment
存在时,应该授予它处理设备后退按钮按下的权限。这很重要,因为 Facebook 登录流程包括离开登录页面的导航功能,并且用户希望返回按钮返回登录。所以,在我的Activity
,我有这个:
@Override
public void onBackPressed()
boolean handled = false;
FacebookWebLoginFragment facebookWebLoginFragment = getFacebookWebLoginFragment();
if (facebookWebLoginFragment != null)
handled = facebookWebLoginFragment.onBackPressed();
if (!handled)
WebViewFragment fragment = getWebViewFragment();
if (fragment != null)
handled = fragment.onBackPressed();
if (!handled)
finish();
FacebookWebLoginFragment
的布局非常简单:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_>
<WebView
android:id="@+id/web_view"
android:layout_
android:layout_
/>
</FrameLayout>
这是FacebookWebLoginFragment
代码。请注意,它依赖于WebChromeClient
的子类来检测 Facebook 登录 JavaScript 何时准备好关闭窗口(即删除片段)。另请注意,此登录 WebView
与包含 cmets UI 的主要 WebView
之间没有直接通信;身份验证令牌通过第三方 cookie 传递,这就是为什么您必须确保在主 WebView
上启用第三方 cookie 支持。
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
import android.os.Message;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import butterknife.Bind;
import butterknife.ButterKnife;
/**
* Hosts WebView used by Facebook web login.
*/
public class FacebookWebLoginFragment extends BaseFragment
private static final String LOGTAG = LogHelper.getLogTag(FacebookWebLoginFragment.class);
@Bind(R.id.web_view) WebView mFacebookLoginWebView;
private WebChromeClient mFacebookLoginWebChromeClient;
private Message onCreateWindowResultMessage;
public static FacebookWebLoginFragment newInstance(Message onCreateWindowResultMessage)
FacebookWebLoginFragment fragment = new FacebookWebLoginFragment();
fragment.onCreateWindowResultMessage = onCreateWindowResultMessage;
return fragment;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
View rootView = inflater.inflate(R.layout.frag_facebook_web_login, container, false);
ButterKnife.bind(this, rootView);
return rootView;
@Override
public void onViewCreated(View v, @Nullable Bundle savedInstanceState)
super.onViewCreated(v, savedInstanceState);
mFacebookLoginWebView.setVerticalScrollBarEnabled(false);
mFacebookLoginWebView.setHorizontalScrollBarEnabled(false);
mFacebookLoginWebView.setWebViewClient(new FacebookLoginWebViewClient());
mFacebookLoginWebView.getSettings().setJavaScriptEnabled(true);
mFacebookLoginWebView.getSettings().setSavePassword(false);
mFacebookLoginWebView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
mFacebookLoginWebChromeClient = makeFacebookLoginWebChromeClient();
mFacebookLoginWebView.setWebChromeClient(mFacebookLoginWebChromeClient);
WebView.WebViewTransport transport = (WebView.WebViewTransport) onCreateWindowResultMessage.obj;
transport.setWebView(mFacebookLoginWebView);
onCreateWindowResultMessage.sendToTarget();
onCreateWindowResultMessage = null; // This seems to eliminate a mysterious crash
@Override
public void onDestroy()
mFacebookLoginWebChromeClient = null;
super.onDestroy();
/**
* Performs fragment-specific behavior for back button, and returns true if the back press
* has been fully handled.
*/
public boolean onBackPressed()
if (mFacebookLoginWebView.canGoBack())
mFacebookLoginWebView.goBack();
else
closeThisFragment();
return true;
private void closeThisFragment()
EventBusHelper.post(new HideFacebookWebLoginEvent());
class FacebookLoginWebViewClient extends WebViewClient
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
// Only allow content from Facebook
Uri uri = Uri.parse(url);
String scheme = uri.getScheme();
if (scheme != null && (TextUtils.equals(scheme, "http") || TextUtils.equals(scheme, "https")))
if (UriHelper.isFacebookHost(uri))
return false;
return true;
private WebChromeClient makeFacebookLoginWebChromeClient()
return new WebChromeClient()
@Override
public void onCloseWindow(WebView window)
closeThisFragment();
;
现在,最棘手的一点是对您现有的WebView
进行必要的更改,因为您可能已经围绕它准备了相当多的代码,并且您需要了解需要做什么改变。
首先,确保您启用了 JavaScript,并且它支持多个窗口。
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportMultipleWindows(true);
您确实不需要需要致电setJavaScriptCanOpenWindowsAutomatically(true)
。
查看其他一些答案,您可能认为您需要使用分配给您的WebView
的WebViewClient
,并覆盖shouldOverrideUrlLoading()
。这不是必需的。重要的是WebChromeClient
,它需要覆盖onCreateWindow()
。
所以...接下来,将自定义 WebChromeClient
子类分配给您的 WebView
:
mWebView.setWebChromeClient(new WebChromeClient()
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg)
String url = null;
Message href = view.getHandler().obtainMessage();
if (href != null)
view.requestFocusNodeHref(href);
url = href.getData().getString("url");
LogHelper.d(LOGTAG, "onCreateWindow: " + url);
// Unfortunately, url is null when "Log In to Post" button is pressed
if (url == null || UriHelper.isFacebookHost(Uri.parse(url)))
// Facebook login requires cookies to be enabled, and on more recent versions
// of Android, it's also necessary to enable acceptance of 3rd-party cookies
// on the WebView that hosts Facebook comments
CookieHelper.setAcceptThirdPartyCookies(mWebView, true);
EventBusHelper.post(new ShowFacebookWebLoginEvent(resultMsg));
else
LogHelper.d(LOGTAG, "Ignoring request from js to open new window for URL: " + url);
return true;
);
您会注意到这是对UriHelper.isFacebookHost()
的第二次调用。我没有万无一失的方法来确定这一点,但这就是我所做的:
public static boolean isFacebookHost(Uri uri)
if (uri != null && !TextUtils.isEmpty(uri.getHost()))
String host = uri.getHost().toLowerCase();
return host.endsWith("facebook.com") || host.endsWith("facebook.net");
return false;
您还会注意到对CookieHelper.setAcceptThirdPartyCookies()
的调用。这是代码:
public static void setAcceptThirdPartyCookies(WebView webView, boolean accept)
CookieManager cookieManager = CookieManager.getInstance();
// This is a safeguard, in case you've disabled cookies elsewhere
if (accept && !cookieManager.acceptCookie())
cookieManager.setAcceptCookie(true);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
cookieManager.setAcceptThirdPartyCookies(webView, accept);
另一件让一些人感到困惑的事情是 Facebook 开发设置中“有效 OAuth 重定向 URI”的配置。如果您在日志中看到这样的错误:
URL 被阻止:此重定向失败,因为重定向 URI 未在应用的客户端 OAuth 设置中列入白名单。确保客户端和 Web OAuth 登录已打开,并将您的所有应用程序域添加为有效的 OAuth 重定向 URI。
...那么你会想看看这个答案:https://***.com/a/37009374
玩得开心!一个看似非常简单的问题的复杂解决方案。从积极的方面来说,Android 为开发者提供了很大的控制权。
【讨论】:
【参考方案6】:上面的答案太旧了,它不适用于最新的 Facebook sdk 2.7 版。在花了 4 个小时之后,我发现它的一些变化。以下代码适用于最新的 SDK。
下面提到的是XML布局文件。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:background="#0099cc"
tools:context=".MainActivity"
android:id="@+id/webview_frame">
<WebView
android:id="@+id/webView"
android:layout_
android:layout_
/>
</FrameLayout>
这是Android Activity代码sn-p
public class MainActivity extends AppCompatActivity
private WebView webView;
private WebView mWebviewPop;
private FrameLayout mContainer;
private Context mContext;
private String url = "https://www.YourWebsiteAddress.com";
private String target_url_prefix = "www.YourWebsiteAddress.com";
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Get outer container
mContainer = (FrameLayout) findViewById(R.id.webview_frame);
webView = (WebView)findViewById(R.id.webView);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setAppCacheEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setSupportMultipleWindows(true);
//These two lines are specific for my need. These are not necessary
if (Build.VERSION.SDK_INT >= 21)
webSettings.setMixedContentMode( WebSettings.MIXED_CONTENT_ALWAYS_ALLOW );
//Cookie manager for the webview
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
webView.setWebViewClient(new MyCustomWebViewClient());
webView.setWebChromeClient(new UriWebChromeClient());
webView.loadUrl("https://www.YourWebsiteAddress.com");
mContext=this.getApplicationContext();
@Override
public void onBackPressed()
if(webView.isFocused() && webView.canGoBack())
webView.goBack();
else
super.onBackPressed();
private class MyCustomWebViewClient extends WebViewClient
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
String host = Uri.parse(url).getHost();
if( url.startsWith("http:") || url.startsWith("https:") )
if(Uri.parse(url).getPath().equals("/connection-compte.html"))
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.YourWebsiteAddress.com"));
startActivity(browserIntent);
return true ;
if (host.equals(target_url_prefix))
if (mWebviewPop != null)
mWebviewPop.setVisibility(View.GONE);
mContainer.removeView(mWebviewPop);
mWebviewPop = null;
return false;
if (host.equals("m.facebook.com") || host.equals("www.facebook.com") || host.equals("facebook.com"))
return false;
// Otherwise, the link is not for a page on my site, so launch
// another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
// Otherwise allow the OS to handle it
else if (url.startsWith("tel:"))
Intent tel = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
startActivity(tel);
return true;
//This is again specific for my website
else if (url.startsWith("mailto:"))
Intent mail = new Intent(Intent.ACTION_SEND);
mail.setType("application/octet-stream");
String AdressMail = new String(url.replace("mailto:" , "")) ;
mail.putExtra(Intent.EXTRA_EMAIL, new String[] AdressMail );
mail.putExtra(Intent.EXTRA_SUBJECT, "");
mail.putExtra(Intent.EXTRA_TEXT, "");
startActivity(mail);
return true;
return true;
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)
Log.d("onReceivedSslError", "onReceivedSslError");
//super.onReceivedSslError(view, handler, error);
@Override
public void onPageFinished(WebView view, String url)
if(url.startsWith("https://m.facebook.com/v2.7/dialog/oauth"))
if(mWebviewPop!=null)
mWebviewPop.setVisibility(View.GONE);
mContainer.removeView(mWebviewPop);
mWebviewPop=null;
view.loadUrl("https://www.YourWebsiteAddress.com");
return;
super.onPageFinished(view, url);
private class UriWebChromeClient extends WebChromeClient
@Override
public boolean onCreateWindow(WebView view, boolean isDialog,
boolean isUserGesture, Message resultMsg)
mWebviewPop = new WebView(mContext);
mWebviewPop.setVerticalScrollBarEnabled(false);
mWebviewPop.setHorizontalScrollBarEnabled(false);
mWebviewPop.setWebViewClient(new MyCustomWebViewClient());
mWebviewPop.getSettings().setJavaScriptEnabled(true);
mWebviewPop.getSettings().setSavePassword(false);
mWebviewPop.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
mContainer.addView(mWebviewPop);
WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
transport.setWebView(mWebviewPop);
resultMsg.sendToTarget();
return true;
@Override
public void onCloseWindow(WebView window)
Log.d("onCloseWindow", "called");
【讨论】:
你能解释一下/connection-compte.html
吗?从 facebook 登录成功后,您将用户发送到这里吗?【参考方案7】:
尝试将您的 webview 移动到 xml 布局文件。空白页错误是由于将 oAuth 登录重定向到授权接受页面时 js 脚本失败导致的。您可以通过将 webview 移动到 xml 布局来解决此问题。
【讨论】:
【参考方案8】:在您的WebViewClient
中覆盖shouldOverrideUrlLoading()
。搜索shouldOverrideUrlLoading
here。此外,还有一个参数可以传递给 facebook 的登录 API;我认为它是redirect_uri。这应该可以帮助您识别登录何时成功并且在您的shouldOVerrideUrlLoading()
中,您只需要检测正在加载的 url,如果它是您指定的 redirect_uri,那么只需在该方法中返回 true 并关闭 webview 或任何您想登录成功的时候。
【讨论】:
【参考方案9】:关于the best answer到this question,只需要实现你使用的WebViewClient类的onPageFinished方法即可。
public void onPageFinished(WebView view, String url)
// First, get the URL that Facebook's login button is actually redirecting you to.
// It should be something simulator to https://www.facebook.com/dialog/return/arbiter?relation=opener&close=true
String webUrl = webView.getUrl();
// Pass it to the LogCat so that you can then use it in the if statement below.
Log.d.println(TAG, webUrl);
if (url.startsWith("The url that you copied from the LogCat"))
// Check whether the current URL is the URL that Facebook's redirecting you to.
// If it is - that's it - do what you want to after the logging process has finished.
return;
super.onPageFinished(view, url);
对我来说效果很好。希望对你也有帮助:)
【讨论】:
以上是关于使 facebook 登录与 Android Webview 一起工作的主要内容,如果未能解决你的问题,请参考以下文章
使用 xmpp 的 Android-facebook 聊天客户端
与 MethodChannel 一起使用的自定义 Facebook 登录