无法在 Android 上使用 asmack 登录 Facebook

Posted

技术标签:

【中文标题】无法在 Android 上使用 asmack 登录 Facebook【英文标题】:unable to login to facebook using asmack on Android 【发布时间】:2012-07-18 11:19:44 【问题描述】:

我正在尝试使用 asmack 和 android 连接到 facebook。我可以连接但无法登录。当我尝试这样做时,我在 super.authenticate(); 上得到了 nullpointerexception 我该如何解决这个问题,请提供一些示例

日志:

 D/tag: connection succeeded
    W/System.err: java.lang.NullPointerException
    W/System.err:   at org.jivesoftware.smack.sasl.SASLMechanism.authenticate(SASLMechanism.java:116)
    W/System.err:   at CustomSASLDigestMD5Mechanism.authenticate(CustomSASLDigestMD5Mechanism.java:36)
    W/System.err:   at org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:319)
    W/System.err:   at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:204)
    W/System.err:   at org.jivesoftware.smack.Connection.login(Connection.java:357)
    W/System.err:   at se.hig.MainActivity.login(MainActivity.java:69)
    W/System.err:   at se.hig.MainActivity.onCreate(MainActivity.java:24)
    W/System.err:   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    W/System.err:   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
    W/System.err:   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
    W/System.err:   at android.app.ActivityThread.access$2200(ActivityThread.java:119)
    W/System.err:   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
    W/System.err:   at android.os.Handler.dispatchMessage(Handler.java:99)
    07-18 10:55:33.384: W/System.err(255):  at android.os.Looper.loop(Looper.java:123)
    07-18 10:55:33.384: W/System.err(255):  at android.app.ActivityThread.main(ActivityThread.java:4363)
    07-18 10:55:33.393: W/System.err(255):  at java.lang.reflect.Method.invokeNative(Native Method)
    W/System.err:   at java.lang.reflect.Method.invoke(Method.java:521)
    W/System.err:   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    07-18 10:55:33.393: W/System.err(255):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    W/System.err:   at dalvik.system.NativeStart.main(Native Method)
    D/tag: login fails exeption : 
    D/tag:  service-unavailable(503)

自定义SASLDigestMD5机制:

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
import org.apache.harmony.javax.security.sasl.Sasl;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.sasl.SASLMechanism;


public class CustomSASLDigestMD5Mechanism extends SASLMechanism


    public CustomSASLDigestMD5Mechanism(SASLAuthentication saslAuthentication)
    
        super(saslAuthentication);
    

    @Override
    public void authenticate(String username, String host, String password)

    throws IOException, XMPPException
    
        this.authenticationId = username;

        this.password = password;
        this.hostname = host;

        String[] mechanisms =  getName() ;
        Map<String, String> props = new HashMap<String, String>();
        sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);    

        super.authenticate();

    

    @Override
    public void authenticate(String username, String host, CallbackHandler cbh)

    throws IOException, XMPPException
    
        String[] mechanisms =  getName() ;

        Map<String, String> props = new HashMap<String, String>();

        sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh);

        super.authenticate();

    

    protected String getName()
    

        return "DIGEST-MD5";

    


主活动:

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity

    private XMPPConnection connection;

    @Override
    public void onCreate(Bundle savedInstanceState)
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        connect();

        login("username", "password");
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    

    public String connect()
    

        ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);

        SASLAuthentication.registerSASLMechanism("DIGEST-MD5", CustomSASLDigestMD5Mechanism.class);

        config.setSASLAuthenticationEnabled(true);
        config.setTruststorePath("/system/etc/security/cacerts.bks");
        config.setTruststoreType("bks");
        config.setDebuggerEnabled(false);

        connection = new XMPPConnection(config);
        try
        
            connection.connect();
            Log.d("tag", "connection succeeded");
         catch (XMPPException e)
        
            Log.d("tag", "connection fails exeption : \n " + e);
        

        // fbml = new FBMessageListener(connection);

        return connection.getConnectionID();

    

    public boolean login(String userName, String password)
    

        if ((connection != null) && (connection.isConnected()))
        
            try
            
                connection.login(userName, password);
             catch (XMPPException e)
            
                Log.d("tag", "login fails exeption : \n " + e);
            

            return true;

        

        return false;

    


【问题讨论】:

【参考方案1】:

它不使用标准的身份验证方法。

见http://developers.facebook.com/docs/chat/

【讨论】:

它说 DIGEST-MD5 应该可以工作,我可以使用 smack 库让代码在 java 中工作。请提供一些例子,以便我更好地理解【参考方案2】:

首先编辑你的 SASLXFacebookPlatformMechanism 类。复制并粘贴此代码。

package com.facebook.android;


import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
import org.apache.harmony.javax.security.sasl.Sasl;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.Base64;

import android.util.Log;

public class SASLXFacebookPlatformMechanism extends SASLMechanism 

    private static final String NAME              = "X-FACEBOOK-PLATFORM";

    private String              apiKey            = "";
    private String              accessToken        = "";

    /**
     * Constructor.
     */
    public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication) 
        super(saslAuthentication);
    

    @Override
    protected void authenticate() throws IOException, XMPPException 
        getSASLAuthentication().send(new AuthMechanism(NAME, ""));
    

    @Override
    public void authenticate(String apiKey, String host, String accessToken) throws IOException, XMPPException 
        if (apiKey == null || accessToken == null) 
            throw new IllegalArgumentException("Invalid parameters");
        

        this.apiKey = apiKey;
        this.accessToken = accessToken;
        this.hostname = host;

        String[] mechanisms =  "DIGEST-MD5" ;
        Map<String, String> props = new HashMap<String, String>();
        this.sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);
        authenticate();
    

    @Override
    public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException 
        String[] mechanisms =  "DIGEST-MD5" ;
        Map<String, String> props = new HashMap<String, String>();
        this.sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh);
        authenticate();
    

    @Override
    protected String getName() 
        return NAME;
    

    @Override
    public void challengeReceived(String challenge) throws IOException 
        byte[] response = null;

        if (challenge != null) 
            String decodedChallenge = new String(Base64.decode(challenge));
            Map<String, String> parameters = getQueryMap(decodedChallenge);

            String version = "1.0";
            String nonce = parameters.get("nonce");
            String method = parameters.get("method");

            String composedResponse =
                "method=" + URLEncoder.encode(method, "utf-8") +
                        "&nonce=" + URLEncoder.encode(nonce, "utf-8") +
                        "&access_token=" + URLEncoder.encode(accessToken, "utf-8") +
                        "&api_key=" + URLEncoder.encode(apiKey, "utf-8") +
                        "&call_id=0" +
                        "&v=" + URLEncoder.encode(version, "utf-8");
            response = composedResponse.getBytes();
        

        String authenticationText = "";

        if (response != null) 
            authenticationText = Base64.encodeBytes(response);
        

        // Send the authentication to the server
        getSASLAuthentication().send(new Response(authenticationText));
    

    private Map<String, String> getQueryMap(String query) 
        Map<String, String> map = new HashMap<String, String>();
        String[] params = query.split("\\&");

        for (String param : params) 
            String[] fields = param.split("=", 2);
            map.put(fields[0], (fields.length > 1 ? fields[1] : null));
        

        return map;
    

然后用这个方法登录脸书聊天

private void testLogin()
        ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
        config.setSASLAuthenticationEnabled(true);
        config.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
        xmpp = new XMPPConnection(config);
        SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM",SASLXFacebookPlatformMechanism.class);
        SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
        Log.i("XMPPClient",
                "Access token to " + mFacebook.getAccessToken());
        Log.i("XMPPClient",
                "Access token to " + mFacebook.getAppId());
        Log.i("XMPPClient",
                "Access token to " + mFacebook.getAccessToken());
        try 
            xmpp.connect();
            Log.i("XMPPClient",
                    "Connected to " + xmpp.getHost());

         catch (XMPPException e1) 
            Log.i("XMPPClient",
                    "Unable to " + xmpp.getHost());

            e1.printStackTrace();
        
        try 
            xmpp.login(PreferenceConnector.APP_ID, mFacebook.getAccessToken());


         catch (XMPPException e) 
            e.printStackTrace();
          
    

【讨论】:

以上是关于无法在 Android 上使用 asmack 登录 Facebook的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 android 的 asmack 库登录 google talk

Asmack/Openfire 401 错误

使用新访问令牌在 android 上使用 asmack 进行 Facebook 聊天

roster.getEntities() 总是返回 null aSmack android

无法使用 asmack 版本 asmack-android-8-4.0.6.jar 在 xmpp 中返回组列表

在 Android 上使用 aSmack 发送和接收自定义 XMPP IQ