Javascript 使用Android网络视图登录facebook

Javascript 使用Android网络视图登录facebook,javascript,android,facebook,webview,Javascript,Android,Facebook,Webview,我只是想在Android的网络视图上实现facebook登录。问题是在我点击HTML页面上的facebook按钮并在facebook对话框中插入用户名和密码之后。url重定向只是给了我一个黑色页面 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WebView webview = new WebView(this);

我只是想在Android的网络视图上实现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对话页面上重定向后,如何获得回复?谢谢。

在您的
WebViewClient
中重写
应该重写的URL()。搜索
应覆盖以下内容
。此外,还有一个参数可以传递到facebook的登录API;我想这是我的错。这将有助于您识别登录成功的时间,在您的
shouldOVerrideUrlLoading()
中,您只需检测正在加载的url,如果它是您指定的重定向uri,然后在该方法中返回true,并在登录成功后关闭webview或任何您想要的内容。

我的android应用程序也有同样的问题。 问题的原因是FB登录javascript在新窗口上打开新页面。登录成功后,它会尝试关闭它并发送一些javascript身份验证代码。WebVIEW通常是“单窗口”,所以它没有地方可以返回,因此空白屏幕。 请遵循我的工作代码中的流程示例

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context=".MyActivity" 
android:id="@+id/webview_frame">

<WebView
    android:id="@+id/webview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>
这个问题的关键是onCreateWindow。将创建一个新窗口,并将其插入框架布局,成功后将其删除。我在shouldOverrideUrlLoading中添加了删除操作。

关于,您只需要实现您使用的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);
} 

这对我来说很好。希望它也能帮助您:)

尝试将您的Web视图移动到xml布局文件。空白页错误是由于JS脚本失败而导致OAuthLogin重定向到授权接受页面。您可以通过将webview移动到xml布局中来解决此问题。

以上答案太旧,并且不适用于最新的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_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context=".MainActivity"
android:id="@+id/webview_frame">

<WebView
    android:id="@+id/webView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    />

</FrameLayout>

我的答案与这里的其他一些答案基本相似,因为我创建了第二个
WebView
来托管Facebook登录页面,而不是试图解决重定向问题。但是,我选择将登录名
WebView
放在它自己的
片段中,并给它自己的
WebViewClient
WebChromeClient
子类。我认为这样可以更容易地看到每个组件所扮演的角色,以及哪些对象需要哪些设置和行为

我还利用
WebChromeClient.onCloseWindow()
来检测Facebook的JavaScript何时想要关闭登录窗口。从一个不同的答案来看,这比我最初采用的方法要稳健得多

活动
布局中,您将有一个“主”
WebView
,它承载注释,以及一个用于
facebook weblogin片段的容器。登录
片段是在需要时动态创建的,然后在Facebook的登录JavaScript请求关闭窗口时删除

我的
活动
布局如下所示:

FacebookWebLoginFragment
存在时,应该授予它处理设备后退按钮的权限。这一点很重要,因为Facebook的登录流包含了从登录页面导航出去的功能,用户希望通过返回按钮返回登录。因此,在我的
活动中
,我有以下几点:

@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_width="match_parent"
             android:layout_height="match_parent">
    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</FrameLayout>
现在,最棘手的一点是对现有的
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

。。。然后,您将要查看以下答案:


玩得开心!一个看似简单问题的复杂解决方案。从积极的一面来看,Android给了开发者大量的控制权。

可能不是一个总是可行的答案,但另一个选择是从“弹出然后JS”风格的OAuth登录切换到非弹出的“重定向uri”OAuth风格,在那里它将他们发送到登录页面,然后在成功/失败后,他们被发送到“某个uri错误其他”(例如:你自己网站上的另一个页面)
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();
            }
        };
    }
}
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportMultipleWindows(true);
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;
    }
});
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;
}
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);
    }
}