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

无法使用android的asmack库登录到google talk,android,oauth-2.0,smack,asmack,google-talk,Android,Oauth 2.0,Smack,Asmack,Google Talk,我一直在尝试使用asmack库登录google talk,但没有成功。我真的不知道幕后发生了什么,只是从这里那里收集了一些代码片段。这是我目前为android活动准备的: public class MainActivity extends Activity { public static final String HOST = "talk.google.com";

我一直在尝试使用asmack库登录google talk,但没有成功。我真的不知道幕后发生了什么,只是从这里那里收集了一些代码片段。这是我目前为android活动准备的:

public class MainActivity extends Activity {                                                          

    public static final String HOST = "talk.google.com";                                              
    public static final int PORT = 5222;                                                              
    public static final String SERVICE = "gmail.com";                                                 
    public static final String USER = "user@gmail.com"; 
    public static final String PASSWORD = "password"; 

    @Override                                                                                         
    public void onCreate(Bundle savedInstanceState) {                                                 
        super.onCreate(savedInstanceState);                                                           
        setContentView(R.layout.main);                                                                
        Context context = getApplicationContext();                                                    
        SmackAndroid asmk = SmackAndroid.init(context);                                               
        SASLAuthentication.registerSASLMechanism("X-OAUTH2", SASLGoogleOAuth2Mechanism.class);        
        SASLAuthentication.supportSASLMechanism("X-OAUTH2", 0);                                       
        ConnectionConfiguration connConfig = new ConnectionConfiguration(HOST, PORT, SERVICE);        
        connConfig.setSecurityMode(SecurityMode.enabled);                                             
        connConfig.setReconnectionAllowed(true);                                                      

        XMPPTCPConnection connection = new XMPPTCPConnection(connConfig);                             
        try {                                                                                         
            connection.connect();                                                                     
            try {                                                                                     
                connection.login(USER, PASSWORD);                         
            } catch (XMPPException ex) {                                                              
                Log.w("XMPPChatDemoActivity", "Failed to log in");                                    
                Log.w("XMPPChatDemoActivity", ex.getMessage());                 
            }                                                                                         
        } catch (...) {                                                                  
           ...
        }
    }
}
这就是萨斯曼机制:

public class SASLGoogleOAuth2Mechanism extends SASLMechanism {

    private static final Logger log = Logger.getLogger("XMPPChatDemoActivity");
    public static final String NAME = "X-OAUTH2";

    public SASLGoogleOAuth2Mechanism(SASLAuthentication saslAuthentication) {
        super(saslAuthentication);
        log.info("Creating SASL mechanism for GTalk (X-OAUTH2)");
    }

    @Override
    public void authenticate(String username, String host, String serviceName, String password) throws IOException, SaslException, NotConnectedException {
        this.authenticationId = username;
        this.hostname = host;
        this.password = password;

        String[] mechanisms = { "PLAIN" };
        Map<String, String> props = new HashMap<String, String>();
        this.sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
        log.info("sc " + sc);
        authenticate();
    }

    @Override
    public void authenticate(String host, CallbackHandler cbh) throws IOException, SaslException, NotConnectedException {
        String[] mechanisms = { "PLAIN" };
        Map<String, String> props = new HashMap<String, String>();

        sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh);
        authenticate();
    }
    @Override
    protected void authenticate() throws IOException, SaslException, NotConnectedException {
        String authenticationText = null;

        try { 
            if (sc.hasInitialResponse()) {
                byte[] response = sc.evaluateChallenge(new byte[0]);
                authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
            }
        } catch (SaslException e) {
            throw new SaslException("SASL authentication failed", e);
        }

        // Send the authentication to the server
        getSASLAuthentication().send(new GoogleOAuthMechanism(authenticationText));
    }
    @Override
    protected String getName() {
        return NAME;
    }
    /**
     * Initiating SASL authentication by select a mechanism.
     */
    public static class GoogleOAuthMechanism extends Packet {
        private final String authenticationText;

        /**
         * Create a GoogleOAuthMechanism.
         *
         * @param authenticationText the authentification token
         *
         */
        public GoogleOAuthMechanism(final String authenticationText) {
            this.authenticationText = authenticationText;
        }

        @Override
        public String toXML() {

            StringBuilder stanza = new StringBuilder();
            stanza.append("<auth mechanism=\"").append(NAME);
            stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
                    + "auth:service=\"oauth2\" "
                    + "xmlns:auth=\"http://www.google.com/talk/protocol/auth\">");
            if (authenticationText != null
                    && authenticationText.trim().length() > 0) {
                stanza.append(authenticationText);
            }
            stanza.append("</auth>");
            return stanza.toString();
        }
    }
}

代码是正常的,我没有得到任何异常,但我得到了一个响应。用户名和密码正确无误。我找不到此库的任何参考代码。任何帮助都将不胜感激。

经过几天的努力,尝试了我在互联网上找到的每一个可以想象的片段组合,我发现了一个解决方案,我很高兴与社区分享

似乎我们不应该将密码传递给XMPPTCPConnection.login方法,而应该使用来自google的auth令牌。我发现了一种生成这样一个令牌的方法。存在一个用于挖掘的方法,但它也使用X-GOOGLE-TOKEN机制进行身份验证,这与使用X-OAUTH2机制进行身份验证的方法不同。此外,我能找到的关于使用OAUTH2对google talk进行身份验证问题的所有其他帖子都是老帖子。我使用的是smack 4.0.4的asmack版本

因此,问题中所示的代码工作所需的唯一修改是:

AccountManager am = AccountManager.get(this);
Account accounts[] = am.getAccountsByType("com.google");
conn.login(USER, amf.blockingGetAuthToken(accounts[0], GOOGLE_TOKEN_TYPE, true));
如您所见,我使用存储在设备上的帐户来验证解决方案,但是您可以通过其他方式生成令牌,正如我在上面所评论的

最后,由于我通过反复试验找到了解决方案,我希望任何人能够解释到底发生了什么或我可能给出的任何错误信息,因此这个答案可以进一步改进