安卓 KitKat 4.4 的 Hangouts 无法处理发送短信意图。

32

发送短信的代码在Android 4.3(果冻豆)之前完美运行,但自从4.4(奇巧巧克力)后就停止工作了。

我只是为用户准备文本消息,但他们需要选择要发送到的号码。

我使用的代码是:

Intent sendIntent = new Intent(Intent.ACTION_VIEW);         
    sendIntent.setData(Uri.parse("sms:"));
    sendIntent.putExtra("sms_body", smsText);

    activity.startActivity(sendIntent);
自从它停止工作以来,我也尝试了ACTION_SENDACTION_SENDTO,但都没有起作用。我还尝试了sendIntent.setType("vnd.android-dir/mms-sms");,但同样无效。
我查看了 Stack Overflow 上的几个答案答案1答案2,但这些答案都没有涉及到我的要求。
我想要做的是:
  • 仅使用短信应用程序发送短信,而不是通过所有提供发送意图的应用程序
  • 为用户准备文本
  • 让用户选择要发送信息的电话号码
对于管理员: 这不是重复的问题,因为该问题没有完全相同的要求,这里的需求是发送没有电话号码的短信,而且没有一个问题和答案涉及到这一点。
4个回答

81

我附上了一段代码,通过以下方式解决问题:

  • 检查操作系统版本
  • 如果是老版本(KitKat之前),使用旧的方法
  • 如果使用新的API,则检查默认的短信包。 如果有任何短信包,请将其设置为包,否则让用户选择共享应用程序。

这是代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) //At least KitKat
    {
        String defaultSmsPackageName = Telephony.Sms.getDefaultSmsPackage(activity); //Need to change the build to API 19

        Intent sendIntent = new Intent(Intent.ACTION_SEND);
        sendIntent.setType("text/plain");
        sendIntent.putExtra(Intent.EXTRA_TEXT, smsText);

        if (defaultSmsPackageName != null)//Can be null in case that there is no default, then the user would be able to choose any app that support this intent.
        {
            sendIntent.setPackage(defaultSmsPackageName);
        }
        activity.startActivity(sendIntent);

    }
    else //For early versions, do what worked for you before.
    {
        Intent sendIntent = new Intent(Intent.ACTION_VIEW);
        sendIntent.setData(Uri.parse("sms:"));
        sendIntent.putExtra("sms_body", smsText);
        activity.startActivity(sendIntent);
    }

1
有没有办法告诉默认的短信应用程序我们想发送消息给哪个联系人?(就像使用添加“smsto:[电话号码]”到URI一样) - dors
1
@dors 我没有测试过,但我会检查 ACTION_SENDTO。这个答案 https://dev59.com/mGIj5IYBdhLWcg3w04Mo?lq=1 谈到了同样的话题,你可能只需要添加 setPackage 调用。 - nheimann1
1
@dors 你可以使用以下代码: Intent sendIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse(uri)); - Brajesh Kumar
1
谢谢大家!我还想提出一个挑战:是否仍然可以传递预定义的文本以在短信消息中显示? - dors
1
@dors 在KitKat上添加EXTRA_TEXT属性确实有效,至少在Hangouts上是这样。 - grahamparks
显示剩余7条评论

19

这个应该适用于所有Android版本以及所有短信应用程序(包括Hangouts)。

public static boolean sendSms(Context context, String text, String number) {
    return sendSms(context, text, Collections.singletonList(number));
}

public static boolean sendSms(Context context, String text, List<String> numbers) {

    String numbersStr = TextUtils.join(",", numbers);

    Uri uri = Uri.parse("sms:" + numbersStr);

    Intent intent = new Intent();
    intent.setData(uri);
    intent.putExtra(Intent.EXTRA_TEXT, text);
    intent.putExtra("sms_body", text);
    intent.putExtra("address", numbersStr);

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        intent.setAction(Intent.ACTION_SENDTO);
        String defaultSmsPackageName = Telephony.Sms.getDefaultSmsPackage(context);
        if(defaultSmsPackageName != null) {
            intent.setPackage(defaultSmsPackageName);
        }
    } else {
        intent.setAction(Intent.ACTION_VIEW);
        intent.setType("vnd.android-dir/mms-sms");
    }

    try {
        context.startActivity(intent);
    } catch (ActivityNotFoundException e) {
        e.printStackTrace();
        return false;
    }

    return true;
}

1
我能用这段代码发送图片吗?我已经尝试使用以下行进行图像附件,但对我来说它不起作用。即smsIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri); - Maroti
如果您能解释如何使intent.putExtra(Intent.EXTRA_STREAM, attachment);工作,那就太好了 :) - sinek

17

将所提出的解决方案相结合,以下提供了预设收件人文本的功能。

Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) // Android 4.4 and up
{
    String defaultSmsPackageName = Telephony.Sms.getDefaultSmsPackage(activity);

    intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:" + Uri.encode(toContact.toString())));
    intent.putExtra("sms_body", text);

    if (defaultSmsPackageName != null) // Can be null in case that there is no default, then the user would be able to choose any app that supports this intent.
    {
        intent.setPackage(defaultSmsPackageName);
    }
}
else
{
    intent = new Intent(Intent.ACTION_VIEW);
    intent.setType("vnd.android-dir/mms-sms");
    intent.putExtra("address", toContact.toString());
    intent.putExtra("sms_body", text);
}
activity.startActivity(intent);
唯一的问题是您最终会进入Hangouts(Nexus 5),您可能需要多次按“返回”才能有效地取消短信。

唯一剩下的问题是你最终会进入Hangouts......这不是真的,只有当用户将其选择为默认短信应用程序时才会进入Hangouts。为了验证您的解决方案,我建议您选择另一个应用程序作为默认短信应用程序,并再次测试您的解决方案(例如尝试Contact+,我相信还有其他应用程序可供选择)。 - nheimann1
抱歉造成误解,问题不在于用户最终进入了Hangouts(如果它被配置为默认的短信客户端),而是需要按多次返回键才能回到之前的界面。我认为这是Hangouts中的一个bug。 - johsin18
后面的问题是,由于Hangouts是按照新的导航指南编写的,如果你问我,只有阅读指南的人才能遵循它。对于普通用户来说,我相信旧的指南更好。你所谓的bug,他们称之为功能(我同意你的看法)。 - nheimann1
1
这个示例在KITKAT上是否调用了两次startActivity? - RoundSparrow hilltx
1
以上代码在搭载Lollipop的Nexus 5上无法正常工作 - Hangouts会打开联系人,但没有预填文本。有人遇到过解决方案吗? - nitzanj
显示剩余2条评论

0
在Kotlin中,以下代码可正常运行:
val defaultSmsPackageName = Telephony.Sms.getDefaultSmsPackage(activity)  
            val sendIntent = Intent(Intent.ACTION_SEND)
            sendIntent.type = "text/plain"
            sendIntent.putExtra("address", "sms:"+contactNumber)
            sendIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_msg_body))
            Timber.e("defaultSmsPackageName: "+defaultSmsPackageName)
            if (defaultSmsPackageName != null){ //Can be null in case that there is no default, then the user would be able to choose any app that support this intent.
                sendIntent.setPackage(defaultSmsPackageName)
                activity!!.startActivity(sendIntent)
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接