結局のところ、SSL 接続にタイムアウトの問題がありました。私のアプリケーションでは、SSL ソケットを生成するのに (プレーン ソケットを介して) 非常に時間がかかり、反対側は単純にあきらめました... これ、またはキーの問題がありました (ただし、認証エラーは発生しませんでした)。
次の方法で問題を解決しました。
- API レベル 15 への移行 - BKS (API 10 で使用した) ではなく、AndroidCSStore を使用します。
- getAuthTokenを使用してパスワードを取得します。これは実際にはトークンですが、後で接続時にパスワードとして使用されます。
- 問題の真相を突き止めるための時間はありません。今は機能しています。それがすべてです。
以下にコードを投稿しました。SASLXOAuth2Mechanism が完成しました。しかし、Main のコードは整然としたものであり、完全ではありません。このサイトの他の回答からコードを抜粋しました。盗作について事前に謝罪します。
Main.java - asmack を開始する
// Init asmack, and register new mechanisms.
asmack = SmackAndroid.init(ctx);
SASLAuthentication.registerSASLMechanism("X-OAUTH2", SASLXOAuth2Mechanism.class);
SASLAuthentication.supportSASLMechanism("X-OAUTH2", 0);
ConnectionConfiguration connectionConfig =
new ConnectionConfiguration (getHost(), getPort(), getService());
connectionConfig.setSASLAuthenticationEnabled(true);
connectionConfig.setSecurityMode(true);
connectionConfig.setRosterLoadedAtLogin(true);
connectionConfig.setReconnectionAllowed(true);
connectionConfig.setSendPresence(false);
//connectionConfig.setCompressionEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
connectionConfig.setTruststoreType("AndroidCAStore");
connectionConfig.setTruststorePassword(null);
connectionConfig.setTruststorePath(null);
} /*else {
connectionConfig.setTruststoreType("BKS");
String path = System.getProperty("javax.net.ssl.trustStore");
if (path == null)
path = System.getProperty("java.home") + File.separator + "etc"
+ File.separator + "security" + File.separator
+ "cacerts.bks";
connectionConfig.setTruststorePath(path);
connectionConfig.setTruststorePassword("changeit");
//} */
XMPPConnection con = new XMPPConnection(connectionConfig);
SASLXOAuth2Mechanism.java - XOAuth2 メカニズム
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.Base64;
import de.measite.smack.Sasl;
public class SASLXOAuth2Mechanism extends SASLMechanism
{
static final String AUTHENTICATOR_URL = "http://www.google.com/talk/protocol/auth";
protected String authenticationText = null;
static final String TAG = "SASLXOAuth2Mechanism";
public SASLXOAuth2Mechanism(SASLAuthentication saslAuthentication) {
super(saslAuthentication);
}
@Override
protected String getName()
{
return "X-OAUTH2";
}
@Override
public void authenticate(String username, String host, String password) throws IOException, XMPPException {
this.password = password;
this.authenticationId = username;
StringBuilder credentials = new StringBuilder();
credentials.append("\0");
credentials.append(username);
credentials.append("\0");
credentials.append(password);
authenticationText = Base64.encodeBytes(credentials.toString().getBytes("UTF-8"), Base64.DONT_BREAK_LINES);
String[] mechanisms = { "PLAIN" };
Map<String,String> props = new HashMap<String,String>();
sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
authenticate();
}
protected void authenticate() throws IOException, XMPPException {
// Send the authentication to the server
getSASLAuthentication().send(new XOAuth2AuthMechanism(getName(), authenticationText));
}
/**
* Initiating SASL authentication by select a mechanism.
*/
public class XOAuth2AuthMechanism extends Packet {
final private String name;
final private String authenticationText;
public XOAuth2AuthMechanism(String name, String authenticationText) {
super();
this.name = name;
this.authenticationText = authenticationText;
}
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=\"").append(AUTHENTICATOR_URL);
stanza.append("\">");
if (authenticationText != null) {
stanza.append(authenticationText);
}
stanza.append("</auth>");
return stanza.toString();
}
}
}