PhoneGap on WP7 Tip #3: Sending SMS and intro to Plugins
In this tip, I’m going to show you how to send an SMS message from PhoneGap on Windows Phone using the SMSCompose member of the Microsoft.Phone.Tasks namespace. There are a lot of useful launchers and choosers in that namespace, and I’ll be writing about some in detail in a future blog post. I’m also using the SMSCompose task to introduce another way to interoperate between your PhoneGap application and the underlying platform, and that is through a PhoneGap plugin.
In the previous tip, I showed how you could write some code in the Silverlight application that is hosting the PhoneGap application, and call it from PhoneGap via the scripting interface. Plugins are simply a different mechanism to invoke platform specific code. The technique is pretty well known to PhoneGap developers already, so it makes sense to explore how to use it in Windows Phone.
PhoneGap has quite a few cross platform APIs in place to handle interop with each platform, in areas such as location, storage, sounds, etc. These are very useful in allowing you to write code that uses those features only once and run it on any device that PhoneGap supports. But, sometimes there are platform specific things you want to take advantage of (and in the case of Windows Phone there are many) so Plugins is a handy way to do that. Jesse MacFayden has also written a great blog post to get you started on writing PhoneGap plugins for Windows Phone.
We’re going to write a plugin to allow us to send an SMS message from JavaScript in PhoneGap using Windows Phone. First, let’s look at the code in C# for sending an SMS message.
SmsComposeTask smsTask = new SmsComposeTask();
smsTask.To = "4045551212";
smsTask.Body = "Message for you, sir!";
smsTask.Show();
Pretty straightforward. Note that in this API, it’s fire-and-forget in that we do not receive a return value. What we’d like to do now is provide a JavaScript function we can call from our PhoneGap application that could invoke that. Maybe we want it to look like this:
sendSMS.send(‘4045551212’, ’Hello’);
Let’s connect those two ends. First of all, we need to put the above C# code into a method in a class that can be called by the PhoneGap runtime. These classes can conveniently be placed in the Plugins folder in your PhoneGap project.
To add the class, right click on the Plugins folder and chose Add New Item. Pick Class and name it whatever you want. I named this one SendSMS.cs. The class has a lot of extra using statements at the top we don’t need, so feel free to remove them for simplicity.
Next, we need to change the namespace. By default, the namespace is our Visual Studio project. However, we want this class to be part of the PhoneGap runtime library’s namespace, so change the namespace at the top of the code to be WP7GapClassLib.PhoneGap.Commands. We also need to change our class to inherit from the PhoneGap runtime’s BaseCommand class so it has all the plumbing in place to be invoked from our JavaScript. So after the name of the class, put : BaseCommand.
Then, inside the class, we need a method to hold our SMS Compose code. I created one called send but you can call it whatever you want. Now we can put the code from above in that method. In order to reference the SmsCompose task we need to bring its namespace reference into our class by adding using Microsoft.Phone.Tasks to the top of the class. By now,you should have something that looks like this:
using Microsoft.Phone.Tasks;
namespace WP7GapClassLib.PhoneGap.Commands
{
public class SendSMS : BaseCommand
{
public void send(string args)
{
SmsComposeTask smsTask = new SmsComposeTask();
smsTask.To = "(678) 555-1212”;
smsTask.Body = "Hello";
smsTask.Show();
}
}
}
Although the recipient and message body are hard-coded, let’s leave that for now so we can get it working.
The next step is to set up a way to invoke this send method from the JavaScript in your PhoneGap application. The way you implement this method is up to you, but most PhoneGap developers will agree that it’s important to provide a consistent way to call Plugins across platforms. To that end, I went out and looked at a list of PhoneGap plugins developed by the community, and I found one that handles sending SMS messages on the iPhone. So I will create a method signature in JavaScript that matches the one for use on iOS. The JavaScript is below (inside of a .js file in your www directory in the project).
function SMSComposer(){
this.resultCallback = null;
}
SMSComposer.prototype.showSMSComposer = function(toRecipients, body)
{
var args = {};
if(toRecipients)
args.toRecipients = toRecipients;
if(body)
args.body = body;
PhoneGap.exec(null, null, "SendSMS", "send", args);
}
PhoneGap.addConstructor(function () {
if (!window.plugins) {
window.plugins = {};
}
window.plugins.smsComposer = new SMSComposer();
}
);
This is a little different from the iPhone one. Since the SmsComposeTask doesn’t return a result, we don’t need any callbacks in JavaScript. The connection point in here is in the PhoneGap.exec call. The first two parameters (currently null) would be the function names that you’d write to handle a callback and an exception coming out of this method call. The third parameter is the name of the C# class, and the fourth is the C# method name. The fifth parameter is a JavaScript object containing any information we want to send to the function we’re calling. For now remember we are ignoring them in our C# code.
With the Plugin’s API in place, just reference that .js file in a <script> tag, and write some JavaScript to call window.plugins.smsComposer.showSMSComposer(recipients, message) with one or more recipient and a message. That’s the same JavaScript you’d write to call the iOS version using that plugin on that platform. By the way, this is what the SMS composer screen will look like to your end users, and if you run your project in the emulator, you’ll see the same thing.
The only thing we have to finish here is to actually make use of the recipient list and message that are sent into the C# function via its args parameter. Since the arguments are coming in as a JSON string, we can use a .NET deserialization library to handle that for us. We create a class that has the data fields that match the JSON object graph (recipients and message) and then deserialize the args parameter into an instance of that class. The deserialization is automatic provided the members of the class match the names and data types of the JSON object graph. Here’s the full version of the C# class with those changes:
using Microsoft.Phone.Tasks;
using System.Runtime.Serialization;
namespace WP7GapClassLib.PhoneGap.Commands
{
public class sendSMSargs
{
[DataMember]
public string toRecipients;
[DataMember]
public string body;
}
public class SendSMS : BaseCommand
{
public void send(string args)
{
sendSMSargs myargs = JSON.JsonHelper.Deserialize<sendSMSargs>(args);
SmsComposeTask smsTask = new SmsComposeTask();
smsTask.To = myargs.toRecipients;
smsTask.Body = myargs.body;
smsTask.Show();
this.DispatchCommandResult();
}
}
}
If you want to use this plugin in other PhoneGap on Windows Phone 7 projects, you’ll just need the C# class file and the JavaScript that calls PhoneGap.exec. As I mentioned, there are many Windows Phone APIs that can be wrapped in plugins for use in PhoneGap, and I’ll be covering some in future blog posts.
There are definitely times you’ll want to use plugins and times you’ll want to use the script interface, and I’ll cover those in more detail in a later post as well. Happy coding!