32

Code for sending sms that worked perfectly until Android 4.3 (Jelly Bean) and stopped working since 4.4 (KitKat)

I'm just preparing the text message for the user, but they need to choose the number to send to.

The code I have used is:

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

    activity.startActivity(sendIntent);

Since it stopped working, I have also tried the ACTION_SEND and ACTION_SENDTO Neither worked, I also tried the sendIntent.setType("vnd.android-dir/mms-sms");, but again nothing worked.

I looked at several answers on Stack Overflow answer 1 and answer 2, but both answers aren't dealing with the requirements I have.

What I would like to do:

  • Send sms with sms app only, not by all apps that serves the send intent
  • Prepare the text for the user
  • Let the user choose the phone number to send the message to

For moderators: It is not a duplicate questions, since the questions, doesn't ask the exact same thing, the need here is to send sms with no phone number, and none of the questions and answers dealt with that.

Shark Lasers
  • 441
  • 6
  • 15
nheimann1
  • 2,348
  • 2
  • 21
  • 33

4 Answers4

80

I attached a code that solve the problem by doing the following:

  • Check the OS version
  • In case that older version (prior to KitKat), use the old method
  • If new API, check the default sms package. if there is any, set it as the package, otherwise, let the user choose the sharing app.

Here is the code:

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);
    }
Kirill Kulakov
  • 10,035
  • 9
  • 50
  • 67
nheimann1
  • 2,348
  • 2
  • 21
  • 33
  • Having the same issue as the user above. Will try this today! :) – Mark Nov 21 '13 at 14:01
  • 1
    Is there a way to also tell the default sms app to which contact we want to send the message? (as was possible using adding "smsto:[phone number] to the uri) – dors Dec 13 '13 at 19:34
  • 1
    @dors I didn't test it, but I would check the ACTION_SENDTO. This answer http://stackoverflow.com/questions/19853220/android4-4-can-not-handle-sms-intent-with-vnd-android-dir-mms-sms?lq=1 is talking about the same topic, you might just need to add the setPackage call. – nheimann1 Dec 14 '13 at 11:52
  • 1
    @dors you can use Intent sendIntent = new Intent (Intent.ACTION_SENDTO, Uri.parse (uri)); – Brajesh Kumar Dec 16 '13 at 12:43
  • 1
    Thanks guys! And I will add one more challenge: is it still possible to pass predefined text to show in the sms message? – dors Dec 16 '13 at 13:48
  • @dors again, I didn't test sending sms with predefined text and number, but I would try the sendIntent.putExtra(Intent.EXTRA_TEXT, smsText) from this answer. I hope it will work, and it would be great if you could write here if it succeeded or not for other people. Good luck – nheimann1 Dec 16 '13 at 14:33
  • 1
    @dors Adding the EXTRA_TEXT property does work on KitKat, with Hangouts at least. – grahamparks Mar 03 '14 at 18:00
  • 1
    Using `text/plain` MIME-type doesn't work on Lollipop. Moreover, Hangouts ignores `sms_body` and `Intent.EXTRA_TEXT` on Lollipop and I didn't manage to find a way to make it work. – Michael Dec 27 '14 at 19:06
  • 1
    @Michael While you need only text body without pre-defined phone number, the code in this answer does work in Lollipop with Hangouts. It doesn't work if you try to add phone number. This is a bug in Hangouts, and currently we couldn't find a solution for the situation when you need both phone number and sms body. The answer above talks about sms body only. If you find a solution, please write it here that other people could use it as well. Happy new year – nheimann1 Dec 29 '14 at 10:07
  • @nheimann1 Yep, I need both body and recipients. And setting `text/plain` as the MIME-type leads to `ActivityNotFoundException`, at least when using `smsto` URI scheme. – Michael Dec 29 '14 at 15:47
  • How to combine this with Whatsapp / Hangouts (chat instead of sms) via phonenumber? – Roel Jul 27 '15 at 09:54
  • Can I send image using this code? I have tried for image attachment using the following line, but it's not working for me. i.e.smsIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri); – Maroti Aug 12 '15 at 13:16
19

This one should work on all android versions and all sms apps (including 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;
}
Roberto B.
  • 3,065
  • 2
  • 18
  • 11
  • 1
    Can I send image using this code? I have tried for image attachment using the following line, but it's not working for me. i.e.smsIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri); – Maroti Aug 12 '15 at 13:16
  • If you can explain how to make intent.putExtra(Intent.EXTRA_STREAM, attachment); work, that'd be great :) – sinek Feb 20 '18 at 13:43
17

Combining the proposed solutions, the following provides presetting the recipient and the text.

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);

The only problem remaining is that you end up in Hangouts (Nexus 5), and you might have to press "back" multiple times to effectively cancel the SMS.

johsin18
  • 838
  • 7
  • 10
  • "The only problem remaining is that you end up in hangouts..." This is not true, you end up in hangouts only if the user choose it as the default sms app. In order to validate your solution, I suggest that you would choose another app to be the default sms app and test your solution again (for example try contact+, I'm sure that there are others too) – nheimann1 Jan 06 '14 at 15:23
  • Sorry for the misunderstanding, the problem is not that the user ends up in Hangouts (if it is configured as the default SMS client), but that you need to press back multiple times to get back. I consider this a bug in Hangouts. – johsin18 Jan 07 '14 at 10:09
  • The back thing is since the hangouts is written with the new navigation guidelines, that if you ask me, only people who read the guideline can follow it. For the common user, I'm sure it was better with the old guidelines. What you call a bug they call a feature (I agree with you) – nheimann1 Jan 07 '14 at 13:56
  • 1
    is startActivity called twice on KITKAT with this sample? – RoundSparrow hilltx Oct 02 '14 at 20:53
  • Thanks for the bug report, fixed. – johsin18 Oct 06 '14 at 06:43
  • 1
    The above code does not work for Nexus 5 with Lollipop - Hangouts opens up on the contact but no pre-populated text. Anyone stumbled upon a solution? – nitzanj Dec 13 '14 at 13:58
  • @nitzanj : yup facing the same issue. Nexus 5 Lollipop Hangouts app basically doesn't take in the sms body text – KG - Dec 17 '14 at 03:21
0

In Kotlin following code works:

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)
            }
Ahmad Shahwaiz
  • 1,432
  • 1
  • 17
  • 35