9

I am having a requirement in my application where i need to integrate messaging in the app. I want to use android native SMS API to send the messages and receive them. The main challenge is that i don't want to show received messages in the Message application. All messages should be opened and send from my application only.

I have tried receiving following intent in my broadcastreceiver :

<intent-filter>
    <action android:name="android.provider.telephony.SMS_RECEIVED"></action>
</intent-filter>

But when the message comes to my application at the same is is received by native Message application, which i don't want.

I have also tried sending data message on a specific port in emulator, it is sending the messgae but not received by my application as well as Message native app on other emulator.

Intent Filter is :

<intent-filter> 
        <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 
        <data android:port="8901"/>
        <data android:scheme="sms"/>
</intent-filter>

I am using the sendDataMessage() function with the given port.

Is it possible send messages in a better and secure way so that there is no possibility to steal your data using the native SMS API in android ? If not what alternate I can go for implementing the same.

Piyush Agarwal
  • 25,608
  • 8
  • 98
  • 111

3 Answers3

10

Here is what I had implemented and its working like exactly what i wanted.

After entering the phone number and Text message call this method .

private static final int MAX_SMS_MESSAGE_LENGTH = 160;
private static final int SMS_PORT = 8901;
private static final String SMS_DELIVERED = "SMS_DELIVERED";
private static final String SMS_SENT = "SMS_SENT";

private void sendSms(String phonenumber,String message) { 

    SmsManager manager = SmsManager.getDefault();
    PendingIntent piSend = PendingIntent.getBroadcast(this, 0, new Intent(SMS_SENT), 0);
    PendingIntent piDelivered = PendingIntent.getBroadcast(this, 0, new Intent(SMS_DELIVERED), 0);

byte[] data = new byte[message.length()];

for(int index=0; index<message.length() && index < MAX_SMS_MESSAGE_LENGTH; ++index)
    {
       data[index] = (byte)message.charAt(index);
    }

manager.sendDataMessage(phonenumber, null, (short) SMS_PORT, data,piSend, piDelivered);

}



 private BroadcastReceiver sendreceiver = new BroadcastReceiver()
 {
         @Override
         public void onReceive(Context context, Intent intent)
         {
                 String info = "Send information: ";

                 switch(getResultCode())
                 {
                         case Activity.RESULT_OK: info += "send successful"; break;
                         case SmsManager.RESULT_ERROR_GENERIC_FAILURE: info += "send failed, generic failure"; break;
                         case SmsManager.RESULT_ERROR_NO_SERVICE: info += "send failed, no service"; break;
                         case SmsManager.RESULT_ERROR_NULL_PDU: info += "send failed, null pdu"; break;
                         case SmsManager.RESULT_ERROR_RADIO_OFF: info += "send failed, radio is off"; break;
                 }

                 Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();

         }
 };

 private BroadcastReceiver deliveredreceiver = new BroadcastReceiver()
 {
         @Override
         public void onReceive(Context context, Intent intent)
         {
                 String info = "Delivery information: ";

                 switch(getResultCode())
                 {
                         case Activity.RESULT_OK: info += "delivered"; break;
                         case Activity.RESULT_CANCELED: info += "not delivered"; break;
                 }

                 Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();
         }
 };

Your Receiver for messages should look like :

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.telephony.SmsMessage;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

public class MySMSReceiver extends BroadcastReceiver {

String action,from,message;

@Override
public void onReceive(Context context, Intent intent) {


     action=intent.getAction();

    Bundle bundle = intent.getExtras();        
    SmsMessage[] msgs = null;


        if(null != bundle)
        {
            String info = "Binary SMS from ";
            Object[] pdus = (Object[]) bundle.get("pdus");
            msgs = new SmsMessage[pdus.length];

            byte[] data = null;

            for (int i=0; i<msgs.length; i++){
                msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);                
                info += msgs[i].getOriginatingAddress();                    
                info += "\n*****BINARY MESSAGE*****\n";
                from= msgs[i].getOriginatingAddress(); 
                data = msgs[i].getUserData();

                for(int index=0; index<data.length; ++index) {
                   info += Character.toString((char)data[index]);
                   message += Character.toString((char)data[index]);
                }
            }

        }

    Intent showMessage=new Intent(context, AlertMessage.class);
    showMessage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    showMessage.putExtra("from", from);
    showMessage.putExtra("message", message);
    context.startActivity(showMessage);

}

}

I have created a simple activity AlertMessage.java to show received message.

The way I registered my broadcast receiver in Manifest :

 <receiver android:name=".MySMSReceiver">
     <intent-filter>
        <action android:name="android.intent.action.DATA_SMS_RECEIVED" /> 
        <data android:scheme="sms" /> 
        <data android:port="8901" />      
     </intent-filter> 
 </receiver>

The port mentioned here must be the same which we specified in method sendSMS() for sending the message.

UPDATE :

Github Repository of working project

https://github.com/pyus-13/MySMSSender

Piyush Agarwal
  • 25,608
  • 8
  • 98
  • 111
  • I did this exactly but it didn't work for me: my app is not able to receive messages at all and also received messages still show in the messaging app. I put a Toast right before `action = intent.getAction();` just to notify when a new message comes in but nothing. – Nii Laryea Mar 03 '14 at 00:55
  • Give a try using different port number. – Piyush Agarwal Mar 03 '14 at 09:15
  • Still didn't work. What code do you use in your `AlertMessage` class to receive the message? – Nii Laryea Mar 07 '14 at 16:13
  • AlertMessage is not responsible for receiving the message, It is just an Activity with two TextViews nothing else. Wait for sometime let me add it in to my github repository. – Piyush Agarwal Mar 07 '14 at 17:21
  • Ok, and don't forget to provide the link here when you're done. – Nii Laryea Mar 07 '14 at 17:55
  • I run your app and when I check the binary checkbox, it seems the message is sent (I know this because my call credit is deducted) but I do not receive the message. Unchecking the checkbox, message is sent and received in the phone's native messaging app. If this works for you, I just can't figure out why I'm having issues with it. – Nii Laryea Mar 10 '14 at 11:02
  • try it in emulator once and let me know. You can use emulator to send and receive SMS and it would be better instead of wasting your money. Make sure the same app is installed in moth of your emulator or device because it was working fine for me on both devices and emulator. – Piyush Agarwal Mar 10 '14 at 14:05
  • I used just a single device, so the text was being sent and received on the same device. It should still work, right? But I'll try with multiple devices and emulators and let you know. – Nii Laryea Mar 10 '14 at 15:00
  • There were some error in package, I made them correct in repository and tested in my Galaxy S2 and was working perfectly. Please delete the older code and take latest code from repository and let me know. – Piyush Agarwal Mar 10 '14 at 19:13
  • If I check the send binary sms checkbox and send a message, the sending is successful and the message is also delivered (according to the Toast displayed). But then the message to be logged in the MySMSReceiver class isn't logged, meaning the app never receives the message. But you said it worked on your device, I don't know why it aint working on mine! – Nii Laryea Mar 15 '14 at 14:07
  • it is working perfectly in my device. If you are getting toast means it is receiving for you too. Instead if log just try to save message in preference in your receiver and toast it on onlaunch on print on activity because I had tried in 4-5 devices and it worked on all. – Piyush Agarwal Mar 15 '14 at 21:04
3

According to me it's possible. You can set higher priority to your app, like

<intent-filter android:priority="100"> 

in your manifest.xml. So that all messages will pass through your app at first and you can store those messages in your database. At the same time, if you are aborting your broadcast, say

abortbroadcast();

you will not get any notifications also on anywhere.

thampi joseph
  • 700
  • 1
  • 8
  • 20
  • I heard about some port to port data messaging can it help ? and what about if another app set priority more than mine ? – Piyush Agarwal Oct 02 '13 at 12:31
  • Sorry I'm not much familiar with that port to port data messaging concept. And for the second question, within my small knowledge the only way i found is to give higher priority to your app. Maybe there will be some other solution. But, this is a way that I know. Hope this will help you my dear friend :) – thampi joseph Oct 02 '13 at 14:54
2

It's not possible to prevent default Messaging application from receiving SMS messages in any way, because your application can't alter other apps' permissions.

Piotr Chojnacki
  • 6,837
  • 5
  • 34
  • 65
  • what can be an alternative way to achieve the same as mentioned ? – Piyush Agarwal Oct 02 '13 at 06:58
  • @pyus13 There is no alternative way on non-rooted devices. The only way is to ignore fact that default messaging app is receiving SMS messages. If user wants to use your app over default one anyway, why do you bother? – Piotr Chojnacki Oct 02 '13 at 07:00
  • my Client don't want that because of some security concern. Is there any third party API to give me the same kind of functionality for both client and server side component to setup a messaging protocol using internet services like XMPP ? – Piyush Agarwal Oct 02 '13 at 07:20
  • @pyus13 I have never heared of anything like this. I'd rather suggest thinking about this 'security' thing, and try to find out if it's really an issue. – Piotr Chojnacki Oct 02 '13 at 07:29