XMPP 带有支持 X-FACEBOOK-PLATFORM 的 Java Asmack 库

2024-03-03

我正在尝试使用 Smack 库在 Android 上进行 Facebook 聊天。我读过Chat API http://developers.facebook.com/docs/chat/来自 Facebook,但我不明白如何使用这个库向 Facebook 进行身份验证。

谁能指出我如何实现这一目标?

Update:根据 no.good.at.coding 答案,我将此代码改编为 Asmack 库。一切正常,除了我收到登录响应:未授权。这是我使用的代码:

public class SASLXFacebookPlatformMechanism extends SASLMechanism
{

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

    private String              apiKey            = "";
    private String              applicationSecret = "";
    private String              sessionKey        = "";

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

    @Override
    protected void authenticate() throws IOException, XMPPException
    {

        getSASLAuthentication().send(new AuthMechanism(NAME, ""));
    }

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

        String[] keyArray = apiKeyAndSessionKey.split("\\|", 2);
        if (keyArray.length < 2)
        {
            throw new IllegalArgumentException(
                    "API key or session key is not present");
        }

        this.apiKey = keyArray[0];
        Log.d("API_KEY", apiKey);
        this.applicationSecret = applicationSecret;
        Log.d("SECRET_KEY", applicationSecret);
        this.sessionKey = keyArray[1];
        Log.d("SESSION_KEY", sessionKey);

        this.authenticationId = sessionKey;
        this.password = applicationSecret;
        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
    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));
            Log.d("DECODED", decodedChallenge);
            Map<String, String> parameters = getQueryMap(decodedChallenge);

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

            long callId = new GregorianCalendar().getTimeInMillis() / 1000L;

            String sig =
                    "api_key=" + apiKey + "call_id=" + callId + "method="
                            + method + "nonce=" + nonce + "session_key="
                            + sessionKey + "v=" + version + applicationSecret;

            try
            {
                sig = md5(sig);
                sig = sig.toUpperCase();
            } catch (NoSuchAlgorithmException e)
            {
                throw new IllegalStateException(e);
            }

            String composedResponse =
                    "api_key=" + URLEncoder.encode(apiKey, "utf-8")
                            + "&call_id=" + callId + "&method="
                            + URLEncoder.encode(method, "utf-8") + "&nonce="
                            + URLEncoder.encode(nonce, "utf-8")
                            + "&session_key="
                            + URLEncoder.encode(sessionKey, "utf-8") + "&v="
                            + URLEncoder.encode(version, "utf-8") + "&sig="
                            + URLEncoder.encode(sig, "utf-8");

            Log.d("COMPOSED", composedResponse);

            response = composedResponse.getBytes("utf-8");
        }

        String authenticationText = "";

        if (response != null)
        {
            authenticationText =
                    Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
        }

        // 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 String md5(String text) throws NoSuchAlgorithmException,
            UnsupportedEncodingException
    {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(text.getBytes("utf-8"), 0, text.length());
        return convertToHex(md.digest());
    }

    private String convertToHex(byte[] data)
    {
        StringBuilder buf = new StringBuilder();
        int len = data.length;

        for (int i = 0; i < len; i++)
        {
            int halfByte = (data[i] >>> 4) & 0xF;
            int twoHalfs = 0;

            do
            {
                if (0 <= halfByte && halfByte <= 9)
                {
                    buf.append((char) ('0' + halfByte));
                }
                else
                {
                    buf.append((char) ('a' + halfByte - 10));
                }
                halfByte = data[i] & 0xF;
            } while (twoHalfs++ < 1);
        }

        return buf.toString();
    }
}

这是通过发送和接收的消息与服务器进行的通信:

PM SENT (1132418216): <stream:stream to="chat.facebook.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">


PM RCV  (1132418216): <?xml version="1.0"?><stream:stream id="C62D0F43" from="chat.facebook.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xml:lang="en"><stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>X-FACEBOOK-PLATFORM</mechanism><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features>


PM SENT (1132418216): <auth mechanism="X-FACEBOOK-PLATFORM" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></auth>


PM RCV  (1132418216): <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">dmVyc2lvbj0xJm1ldGhvZD1hdXRoLnhtcHBfbG9naW4mbm9uY2U9NzFGNkQ3Rjc5QkIyREJCQ0YxQTkwMzA0QTg3OTlBMzM=</challenge>


PM SENT (1132418216): <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">YXBpX2tleT0zMWYzYjg1ZjBjODYwNjQ3NThiZTZhOTQyNjVjZmNjMCZjYWxsX2lkPTEzMDA0NTYxMzUmbWV0aG9kPWF1dGgueG1wcF9sb2dpbiZub25jZT03MUY2RDdGNzlCQjJEQkJDRjFBOTAzMDRBODc5OUEzMyZzZXNzaW9uX2tleT0yNjUzMTg4ODNkYWJhOGRlOTRiYTk4ZDYtMTAwMDAwNTAyNjc2Nzc4JnY9MS4wJnNpZz04RkRDRjRGRTgzMENGOEQ3QjgwNjdERUQyOEE2RERFQw==</response>


PM RCV  (1132418216): <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>

正如在开发者 Facebook 论坛 http://forum.developers.facebook.net/viewtopic.php?id=93219,需要从应用程序的 Facebook 设置页面禁用“禁用已弃用的身份验证方法”设置。但是,即使这样做,我也无法登录。会话密钥是 OAuth 令牌的第二部分,格式为 AAA|BBB|CCC,我的意思是 BBB。


最后,感谢 no.good.at.coding 代码和 harism 的建议,我已经能够连接到 Facebook 聊天了。此代码是 Asmack 库(Android 的 Smack 端口)的机制。对于Smack库来说有必要使用no.good.at.coding机制。

SASLXFacebookPlatformMechanism.java:

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;

public class SASLXFacebookPlatformMechanism extends SASLMechanism
{

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

    private String              apiKey            = "";
    private String              applicationSecret = "";
    private String              sessionKey        = "";

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

    @Override
    protected void authenticate() throws IOException, XMPPException
    {

        getSASLAuthentication().send(new AuthMechanism(NAME, ""));
    }

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

        String[] keyArray = apiKeyAndSessionKey.split("\\|", 2);
        if (keyArray.length < 2)
        {
            throw new IllegalArgumentException(
                    "API key or session key is not present");
        }

        this.apiKey = keyArray[0];
        this.applicationSecret = applicationSecret;
        this.sessionKey = keyArray[1];

        this.authenticationId = sessionKey;
        this.password = applicationSecret;
        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");

            long callId = new GregorianCalendar().getTimeInMillis();

            String sig =
                    "api_key=" + apiKey + "call_id=" + callId + "method="
                            + method + "nonce=" + nonce + "session_key="
                            + sessionKey + "v=" + version + applicationSecret;

            try
            {
                sig = md5(sig);
            } catch (NoSuchAlgorithmException e)
            {
                throw new IllegalStateException(e);
            }

            String composedResponse =
                    "api_key=" + URLEncoder.encode(apiKey, "utf-8")
                            + "&call_id=" + callId + "&method="
                            + URLEncoder.encode(method, "utf-8") + "&nonce="
                            + URLEncoder.encode(nonce, "utf-8")
                            + "&session_key="
                            + URLEncoder.encode(sessionKey, "utf-8") + "&v="
                            + URLEncoder.encode(version, "utf-8") + "&sig="
                            + URLEncoder.encode(sig, "utf-8");

            response = composedResponse.getBytes("utf-8");
        }

        String authenticationText = "";

        if (response != null)
        {
            authenticationText =
                    Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
        }

        // 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 String md5(String text) throws NoSuchAlgorithmException,
            UnsupportedEncodingException
    {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(text.getBytes("utf-8"), 0, text.length());
        return convertToHex(md.digest());
    }

    private String convertToHex(byte[] data)
    {
        StringBuilder buf = new StringBuilder();
        int len = data.length;

        for (int i = 0; i < len; i++)
        {
            int halfByte = (data[i] >>> 4) & 0xF;
            int twoHalfs = 0;

            do
            {
                if (0 <= halfByte && halfByte <= 9)
                {
                    buf.append((char) ('0' + halfByte));
                }
                else
                {
                    buf.append((char) ('a' + halfByte - 10));
                }
                halfByte = data[i] & 0xF;
            } while (twoHalfs++ < 1);
        }

        return buf.toString();
    }
}

使用方法:

ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
config.setSASLAuthenticationEnabled(true);
XMPPConnection xmpp = new XMPPConnection(config);
try
{
    SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM", SASLXFacebookPlatformMechanism.class);
    SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
    xmpp.connect();
    xmpp.login(apiKey + "|" + sessionKey, sessionSecret, "Application");
} catch (XMPPException e)
{
    xmpp.disconnect();
    e.printStackTrace();
}

apiKey 是 Facebook 的应用程序设置页面中给出的 API 密钥。 sessionKey 是访问令牌的第二部分。如果令牌采用以下形式:AAA|BBB|CCC,则 BBB 是会话密钥。 sessionSecret 是使用旧的 REST API 和 auth.promoteSession 方法获得的。要使用它,需要通过 Http 访问此 url:

https://api.facebook.com/method/auth.promoteSession?access_token=yourAccessToken https://api.facebook.com/method/auth.promoteSession?access_token=yourAccessToken

尽管 Facebook 聊天文档说需要使用您的应用程序密钥,但只有当我使用返回 REST 方法的密钥时,我才能使其工作。要使该方法起作用,您必须禁用禁用已弃用的身份验证方法应用程序设置中“高级”选项卡中的选项。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

XMPP 带有支持 X-FACEBOOK-PLATFORM 的 Java Asmack 库 的相关文章

  • 匿名类上的 NotSerializedException

    我有一个用于过滤项目的界面 public interface KeyValFilter extends Serializable public static final long serialVersionUID 7069537470113
  • 在 Netbeans 8 上配置 JBoss EAP 的问题

    我已经下载了 JBoss EAP 7 并正在 Netbeans 8 上配置它 我已经到达向导 实例属性 其中要求从选择框中选择 域 当我打开选择框时 它是空的 没有什么可以选择的 因此 完成 按钮也处于非活动状态 这使得无法完成配置 我通过
  • 在旋转时从错误的资源文件夹中提取可绘制对象

    在这里拉我的头发 因此 我正在使用一个具有多种类型的可绘制对象的应用程序 并且它们的结构如下 res Portrait resources drawable mdpi drawable hdpi drawable xhdpi Landsca
  • Android:滚动 Horizo​​ntalScrollView 时如何禁用 ScrollView 的垂直滚动?

    我正在开发一个带有带有 ScrollView 的 Activity 的 Android 应用程序 其中包含 Horizo ntalScrollView 等内容 当我触摸 Horizo ntalScrollView 时 我想禁用外部 Scro
  • 很好地处理数据库约束错误

    再一次 它应该很简单 我的任务是在我们的应用程序的域对象中放置一个具有唯一约束的特定字段 这本身并不是一个很大的挑战 我刚刚做了以下事情 public class Location more fields Column unique tru
  • PhoneStateListener 不调用

    这是我的完整代码 广播示例 java package com example broadcast gt import android app Activity import gt android content Context import
  • Javafx过滤表视图

    我正在尝试使用文本字段来过滤表视图 我想要一个文本字段 txtSearch 来搜索 nhs 号码 名字 姓氏 和 分类类别 我尝试过在线实施各种解决方案 但没有运气 我对这一切仍然很陌生 所以如果问得不好 我深表歉意 任何帮助将不胜感激 我
  • IntelliJ - 调试模式 - 在程序内存中搜索文本

    我正在与无证的第三方库合作 我知道有一定的String存储在库深处的某个字段中的某处 我可以预测的动态值 但我想从库的 API 中获取它 有没有一种方法可以通过以下方式进行搜索 类似于全文搜索 full程序内存处于调试模式并在某个断点处停止
  • 如何在 Viewpager 中禁用预加载下一页? [复制]

    这个问题在这里已经有答案了 如何在 Viewpager 中禁用页面预加载 I tried viewPager setOffscreenPageLimit 0 但它不起作用 用这个viewPager setOffscreenPageLimit
  • 在 Spring 中重构这个的最佳方法?

    private final ExecutorService executorParsers Executors newFixedThreadPool 10 public void parse List
  • 哪些 Flutter 插件或功能可以利用外部 iOS/Android 显示器来显示与主显示器不同的内容

    我正在构建一个跨平台应用程序 需要在外部显示器上显示不同的视图 通常通过连接到 LCD 投影仪的 HDMI 适配器电缆连接 Flutter 是否能够在内置的外部显示器上显示不同的屏幕 在现有的 Flutter 插件中还是使用现有的 Flut
  • java.lang.NumberFormatException: Invalid int: "3546504756",这个错误是什么意思?

    我正在创建一个 Android 应用程序 并且正在从文本文件中读取一些坐标 我在用着Integer parseInt xCoordinateStringFromFile 将 X 坐标转换为整数 Y 坐标的转换方法相同 当我运行该应用程序时
  • 我可以创建自定义 java.* 包吗?

    我可以创建一个与预定义包同名的自己的包吗在Java中 比如java lang 如果是这样 结果会怎样 这难道不能让我访问该包的受保护的成员 如果不是 是什么阻止我这样做 No java lang被禁止 安全管理器不允许 自定义 类java
  • 如何在android asynctask中使用inputstream作为参数?

    我正在制作一个 Android 应用程序来跟踪股票详细信息 我将通过 csv 雅虎财经 检索数据 据我所知 在android 4 0中 网络连接无法在主线程上完成 因此 我将使用 asynctask 来建立连接 但是 我在参数方面遇到了一些
  • 替换后增量

    我自己已经有一个问题了 但我想扩展它后增量示例 https stackoverflow com questions 51308967 post increment with example char a D int b 5 System o
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 在 KitKat 4.4.2 中获取 SDard 路径和大小

    我在 Google Play 上有一个设备信息应用程序 在该应用程序中我有存储信息 我知道 Android 4 4 在访问外部 SD 卡方面发生了一些变化 内部似乎没有给我带来问题 我的问题是 如何可靠地获取 KitKat 上 SD 卡的大
  • Java中的Object类是什么?

    什么是或什么类型private Object obj Object http download oracle com javase 6 docs api java lang Object html是Java继承层次结构中每个类的最终祖先 从
  • javafx android 中的文本字段和组合框问题

    我在简单的 javafx android 应用程序中遇到问题 问题是我使用 gradle javafxmobile plugin 在 netbeans ide 中构建了非常简单的应用程序 其中包含一些文本字段和组合框 我在 android
  • 尝试将 SQLite DB 从数据复制到 SD 卡

    我正在使用以下代码 该代码发布在 Stack Overflow 上的某个位置 并根据我的目的进行了修改 try File sd Environment getExternalStorageDirectory File data Enviro

随机推荐

  • 实现 HTML5 视频的最佳方式

    我知道 HTML5 视频比其支持者希望我们相信的要复杂得多 Safari 使用专有的 H 264 编解码器 而 Firefox Chrome 和 Opera 都支持开源 Theora Internet Explorer 两者都不支持 因此需
  • 使用卷积神经网络进行四边形/矩形检测的想法

    I v been trying to do quadrangle detection and localization for weeks my goal is to have a robust way of getting the 4 p
  • 在 Delphi 版本 <= 2007 中处理 Unicode 字符串

    背景 这个问题涉及2009年以下的Delphi版本 即没有内置的Unicode支持 我有一个规范要求我通过 TCP 连接传输 Unicode 编码的字符串 但我没有 Delphi 2009 Question是否有一个函数或非常小的库 我不需
  • php 5.3 CLI 垃圾字符

    我面临的问题是 每当我从命令行运行一个简单的 php 脚本时 它前面都会显示一些垃圾字符 我在 Windows 7 上的 wamp 服务器上使用 php 5 3 9 这是我的脚本代码 这是我在 cli 中得到的 Hi 让我知道是否有其他人遇
  • 帆布滴管

    我需要实现一个吸管工具 我想要它 所以您单击吸管按钮将其激活 然后使用 onmove 它将更改我的颜色选择器的颜色 当您单击使用 onclick 时 它将使用以下方法将颜色设置为颜色选择器 colorpickerHolder ColorPi
  • 如何为 Windows 安装 libpq-dev 软件包

    我知道如何为 ubuntu 安装 libpq dev 但我查看了过去的问题 但无法找到如何为 Windows 安装该软件包 有没有地方可以下载该软件包或下载它的安装程序 我不知道 Windows 是否有一个 包 但你可以在这里下载 post
  • 在pyspark中按行连接字符串

    我有一个 pyspark 数据框 DOCTOR PATIENT JOHN SAM JOHN PETER JOHN ROBIN BEN ROSE BEN GRAY 并且需要按行连接患者姓名 以便得到如下输出 DOCTOR PATIENT JO
  • 模糊 MAAttachedWindow 后面的背景?

    只是好奇这是否可能 现在这是一个示例MAAttachedWindow http mattgemmell com 2007 10 03 maattachedwindow nswindow subclass好像 不过我想知道是否可以模糊背景be
  • Rails 3 在“lib”目录中看不到我的类

    我已放置文件rack app rb与简单的机架应用程序lib目录 class RackApp def call env 200 Hello end end 然后我添加了这条路线 match rack gt RackApp 当我尝试启动 Ra
  • 从 PDF 文件中提取文本数据

    是否可以在 R 中解析 PDF 文件中的文本数据 那里似乎不是此类提取的相关包 http crantastic org search q parse pdf 但是有人尝试过或见过 R 中这样做吗 In Python中有PDFMiner ht
  • 如何查明 Prolog 是否执行尾调用优化

    使用SWI Prolog Win x64 的开发版本 我为 a 编写了一个 DCG 谓词确定性词法分析器 托管在 github 上 https github com sebgod goldparser prolog 因此所有外部谓词都没有留
  • 在 Perl 中获取按修改日期排序的文件列表

    我正在尝试获取按修改日期排序的文件列表 我修改了示例程序根据日期和时间对目录进行排序并列出文件 http forums devshed com perl programming 6 sort directory and list files
  • 使用loopj Android异步Http客户端同步调用

    在一种情况下 我尝试在 Loopj 上使用 setUseSynchronousMode 来等待 http 调用的结果 然后再继续 我试过 AsyncHttpResponseHandler responseHandler new AsyncH
  • 如何尽可能快地生成此 switch 语句?

    2009 12 04 更新 有关此处发布的一些建议的分析结果 请参见下文 问题 考虑以下非常无害 非常简单的方法 它使用switch返回定义的枚举值的语句 public static MarketDataExchange GetMarket
  • 单元测试项目中的连接字符串到 app_data 文件夹中的引用数据库

    我希望在单元测试项目中引用我的数据库文件 这是一个 ASP NET MVC 应用程序 请注意 我知道我不应该在单元测试中访问数据库 但这是为了快速修复我现在需要通过的一项测试 在下一个里程碑之后 我将嘲笑数据库访问方法等 这是我的 mvc
  • 在 Groovy 1.7 中使用具有混合内容的 HTML 构建器的正确语法是什么?

    On the Groovy 示例页面 https web archive org web 20100712132418 http groovy codehaus org Builders有一个示例说明如何使用具有混合内容的 Groovy H
  • Android:使用自定义键盘编辑文本

    我按照 sdk 中的示例创建了自己的自定义键盘 现在我想在我的应用程序中的 EditText 上默认使用这个自定义键盘 实际上我必须长按 edittext 然后选择我的custom keyboard 我怎样才能做到这一点 似乎与 input
  • 猜测无界整数

    如果我对你说 我正在想一个0到n之间的数字 我会告诉你你的猜测是高还是低 然后你会立即进行二分查找 如果我删除上限怎么办 即我正在考虑一个正整数 你需要猜测它 一种可能的方法是让您猜测 2 4 8 直到您对某些 k 猜测 2 k 并且我说
  • Pod 无法安装软件包(apt-get update 或 apt-get install )

    我发现集群中的 pod 在 exec 到 pod 时无法安装软件包 在调试时我意识到这是由于 etc resolv conf entries The etc resolv conf 其中一个 Pod 的条目是 nameserver 192
  • XMPP 带有支持 X-FACEBOOK-PLATFORM 的 Java Asmack 库

    我正在尝试使用 Smack 库在 Android 上进行 Facebook 聊天 我读过Chat API http developers facebook com docs chat 来自 Facebook 但我不明白如何使用这个库向 Fa