08.14.07

Sending and receiving GSM SMS on Blackberry using RIM APIs

Posted in J2ME at 9:33 pm by nick

One of the most interesting aspects of the mobile applications is the asynchronous messaging. SMS messages, despite their small size and other limitations represent a very important mechanism the applications can use for various purposes: sending small connectionless notifications from the client to the server, waking up the inactive application on the user’s device, making payments, chunked data exchange (like used in Wireless Village protocol) etc. Unfortunately, the Wireless Messaging API (WMA API for MIDP) has very limited capabilities when it comes to customizing the message format and the payload. RIM Blackberry devices offer much richer (and not very well documented) access to the SMS features. This article explains how to control various parameters of the GSM SMS from Java ME application on these devices.

Quick links


WMA way

As you know, sending SMS using WMA API is very easy. All you need is to open an SMS "client connection", then create a message object for BINARY or TEXT (and since WMA 2.0 - MULTIPART) message, put the payload into this object and send it. Something like this:

MessageConnection conn =
	(MessageConnection)Connector.open("sms://18001234567:5678");
BinaryMessage msgOut = conn.newMessage(MessageConnection.BINARY_MESSAGE);
msgOut.setPayloadData("my binary payload".getBytes("UTF-8"));
conn.send(msgOut);

And this is maximum you can do (which is enough in some cases). However, you never know how does this particular J2ME implementation will format your message and where it is going to be sent - all this is defined by the phone configuration, operator and the skill level of the developer who implemented this functionality.


Sending SMS using RIM API

Blackberry allows you to use WMA API just like on any MIDP 2.0 phone and also offers its own datagram-based API for dealing with the SMS.

Let define first what do we want to achieve:

  • we want to send a binary single-part message
  • we want to have customized the UDH (User Data Header)
  • we want to set some SMS parameters like Message Class, Encoding,
    Delivery Period

First of all, unlike in WMA API, on Blackberry you have to use javax.microedition.io.DatagramConnection class for your connection instead of MessageConnection. I believe it does make sense since SMS message definitely fits into the definition of the datagram, at least from the developer’s perspective.

DatagramConnection smsConnection =
	(DatagramConnection)Connector.open("sms://18001234567:9876");
// tricky part - creating SmsAddress object
SmsAddress destinationAddr = new SmsAddress("//18001234567:9876");

The code quoted above uses some not-so-well-documented RIM classes. For example, net.rim.device.api.io.SmsAddress. Just read the javadocs for this class and you will understand what I am talking about. For example, one of the parameters for one of the methods is documented as "A string representing the SMS address in the format described in the SMSAddress class description.". Guess what you can find in the class description ;)

Next part is more straightforward. We just need to configure the SMS header. Your SmsAddress object (this is not obvious) actually contains the SMS header. net.rim.device.api.system.SMSPacketHeader class is a very interesting one, you will be impressed once you see the javadocs. The key phrase is the second (and the last sentence) in the class description - "See GSM 03.40 for details" This is the ETSI specification where you will find the detailed description of all the header fields in the SMS. We will stick to the original goal and just set a couple of parameters.

SMSPacketHeader header = destinationAddr.getHeader();
// no need for the report
header.setStatusReportRequest(false);
// we are going to use the UDH
header.setUserDataHeaderPresent(true);
// setting the validity and delivery periods
header.setValidityPeriod(SMSParameters.PERIOD_INDEFINITE);
header.setDeliveryPeriod(SMSParameters.PERIOD_INDEFINITE);
// setting the message class
header.setMessageClass(SMSParameters.MESSAGE_CLASS_1);
// setting the message encoding - we are going to send UTF-8 characters so
// it has to be 8-bit
header.setMessageCoding(SMSParameters.MESSAGE_CODING_8_BIT);

There are some methods that you may find useful defined in the net.rim.device.api.io.DatagramConnectionBase class. You have to cast your DatagramConnection instance to get to it.

Now it is time to take care about the payload. Note: the UDH header is actually a part of the payload, not the SMS header. The only thing related to the UDH is the flag that the message DOES HAVE UDH (we have set it to "true"). Also, if you use UDH, you have to use 8-bit encoding.

int maxDatagramLength = smsConnection.getMaximumLength();
// note - I have seen this method returning some strange
// values. If it returns anything bigger than 140 you have
// to limit your message size to 140 bytes
final byte myUDH = new byte[] {
0x06,
0x05,   // application addressing scheme
0x04,   // address size in bytes: 2 x 2 bytes
0x04, 0xd2, // destination port=1234, little-endian
0x04, 0xd2  // source port=1234, little-endian
};
// calculating the remaining space for the data
maxDatagramLength -= myUDH.lenth;
byte[] message = "Bonjour de Montréal".getBytes("UTF-8");
// building the actual SMS payload
byte[] completePayload = new byte[myUDH.length + message.length];
System.arraycopy(myUDH, 0, completePayload, 0, myUDH.length);
System.arraycopy(message, 0, completePayload,
	myUDH.length, message.length);

The message is almost ready. All we need to do is to wrap it into a Datagram (javax.microedition.io.Datagram) and send it:

// allocating new datagram
Datagram d = smsConnection.newDatagram(completePayload.length);
// tricky part to set the destination, will not work without this call
((DatagramBase)d).setAddressBase(destinationAddr);
// now adding the payload with the UDH to the datagram
d.setData(completePayload, 0, completePayload.length);
// and finally sending it
smsConnection.send(d);

Of course, the code has to take care of all possible exceptions that may be thrown by these methods. Asynchronous I/O is still I/O.


Handling incoming SMS on Blackberry

Receiving SMSes is much easier then sending, primarily since someone has already taken care of sending them properly - otherwise you will have nothing to receive :)

In WMA API you have two options for receiving asynchronous notifications: you can either register a listener that will be called every time something comes in (MessageConnection.setMessageListener()) or just calling MessageConnection.receive() from a separate thread. In either case it will cost you a thread so these options are not that much different.

When using Blackberry API everything starts with opening a "server" connection:

DatagramConnection incomingConnection =
	(DatagramConnection)Connector.open("sms://:1234");
// starting a thread to handle the reading
...

After that you need to just run a loop around the code like this:

while(...) {
	try {
		Datagram sms = incomingConnection.newDatagram(
			incomingConnection.getMaximumLength());
		// ...
		// this call will block
		incomingConnection.receive(sms);
		byte[] payload = sms.getData();
	} catch (IOException) {
		// ...
	} catch (SecurityException) {
		// ...
	} catch (Throwable t) {
		// ...
	}
}

You can analyze the SMS headers using the same methods as we used when sending out the messages if you really want to make sure it is an SMS for your application. However, since only one application can open a port at the same time, this kind of verification would be extra.

Since I have written these paranoid "catch" blocks, I have to explain why did I do it. Unfortunately, I have to state that Blackberry SMS API is not reliable and at different points on different devices may demonstrate very strange behavior. So:

  • You absolutely need to catch IOException. However, an IOException does not really indicate a permanent non-recoverable error. I would suggest to count the number of consecutive exceptions and if it exceeds certain threshold - close the connection and initiate self-destruct sequence for the device ;) Or at least to inform the user that the application cannot receive the notifications.
  • SecurityException has to be handled in a special way. Unlike IOException, this exception indicates that the application is not allowed to receive the SMS (at least on this port). Do not ask me why you get it only after first attempt to receive a datagram, not after opening the server connection :) One more note about this exception: in some of the devices it has been replaced with an IOException with the message "Permission denied" which makes it even harder to write proper code…
  • Throwable. I have seen the SMS connections throwing various exceptions - from NullPointerException to IllegalStateException. Usually it happens when the device state changes, especially when the device is restarted. I would suggest to apply the same pattern as for the IOException and consider certain threshold.
  • Finally, it is highly recommended to put a wait() for at least a couple of hundreds of milliseconds after any error condition detected.

One more note about receiving the SMS and restarting the device. Some older versions of Blackberry firmware may attempt to push you the messages that you have already received and processed before. Especially if the SMSes are stored on the SIM card. You may need to implement a filter that will discard these duplicates.


What is about the Push Registry?

In order to have the complete story I need to explain how to make sure that your application always receives the SMSes. This is important for any application since the SMS can be delayed for a couple of hours, arrive twice etc. And if there is no application is listening for the target port (assuming the SMS with UDH), it will go straight to the inbox, which is highly undesirable.

In MIDP you could use "Push Registry" mechanism that would "register" certain port number (possibly with the additional filter for the source phone number) with the platform so it would automatically start the application upon receiving the message matching the filter. By the way, do not try this method with Blackberries if you are writing MIDlets - most likely you will be surprised :(

Blackberry applications have to start automatically (this option is available for the application modules on Blackberry) when the device starts and run in the background until next reboot. Upon startup the application should open the incoming connection and then enter the loop waiting for the incoming messages. Here is a couple of advises for writing this kind of "daemons":

  • Split your application into two parts. Small part (the "daemon" will be responsible just for the receiving of the SMSes. Once it receives a message and if the main part (UI-based) is not running it would start it. Then even if UI application exits completely (to release the memory) the application will still be ready to react to the incoming notifications.
  • Make sure your "daemon" is 100% reliable, does not cause any infinite loops, does not crash and does not contain any memory leaks.
  • You can exchange the data (even between the processes) on Blackberry by using net.rim.device.api.system.RuntimeStore.


References

  1. ETSI (European Telecommunications Standards Institute)
  2. Blackberry Developer Resources
  3. Wireless Messaging API (JSR-120, JAR-205) home
  4. RIM Device Java Library 4.1

7 Comments »

  1. SMSPacketHeader recieved sms. - BlackBerryForums.com : Your Number One BlackBerry Community said,

    June 9, 2008 at 10:38 pm

    [...] of the sms such as ProtocolId. SMSPacketHeader from the BB API allows you to do this. I’ve only found one tutorial that says it’s possible to use, but I can’t get it to work: [...]

  2. Joe said,

    November 18, 2008 at 5:41 am

    Very useful article for me. Thank you very much.

  3. Sasikumar said,

    March 20, 2009 at 9:43 am

    Hi.

    I am using the Blackberry 8300 Mobile, while i send the special symbols, it will not send the exact symbol, it send the another symbol (example @=i, *=?). I am using the Messageconnection and Textmessage format in J2me api (Javax). could you tell me the another way to send the special symbol, I need to send text message no need the binary message format.

    Thanks
    Sasi

  4. Berlard said,

    April 12, 2009 at 3:58 am

    Hi,

    I just have a question, when i use MessageListener to listen a incoming short message, every time it prompt ‘.. has attempted to send or receive messages with the network. Would you like to allow this?’, i just don’t know how to configure or use rim api ignore it.

    Thanks

  5. Nick said,

    April 12, 2009 at 9:38 am

    Berlard,

    This is a security restriction. Normally it would happen once, when you register the listener, open an HTTP connection (although there you can select “always allow”) etc. The only way to get rig of this message is to sign the application.

  6. Joe said,

    September 12, 2009 at 5:27 am

    Thank you very much for the article. Avery thing is working fine for me sending and receiving, except one issue.Since we are using MESSAGE_CODING_8_BIT in the api it is said like this

    “” MESSAGE_CODING_8_BIT
    public static final int MESSAGE_CODING_8_BIT8-bit (user-defined) message coding.
    The message has user-defined coding, and can consist of up to 140 bytes. “”

    The problem is that when we tried to send a sms say 120 characters the sms goes from the phone(i am using simulator -9530 JDE, for testing) but the sms received on the phone has only 89 characters it has been trimmed.
    Have any one tried sending a big sms. can u please give a comment.

    Is this the problem with the simulator or DatagramConnection .
    Can any one help me to sort the problem

  7. Sudhakar Chavali said,

    January 18, 2010 at 1:55 am

    Hi

    Thanks for sharing nice article

    I have few questions that need clarification. Can you help me on this?
    1. Do I need to mention port explicitly while creating connection object? I was reading a discussion in verizon developers forum where it was mentioned that I need to append port 0 to url.
    Source: http://developer.verizon.com/forum/posts/list/645.page;jsessionid=B03609F47724D7EA6EFC3A54814EAE18#2109

    2. what is the difference in sms://18001234567:9876 Vs sms://18001234567

    3. (Sending SMS using RIM API) — Will this work both for CDMA and GSM devices?

    4. When shall I use WMA way? Because Event Blackberry supports this API.

    Thanks
    Sudhakar Chavali

Leave a Comment

Spam protection by WP Captcha-Free