We recently worked on porting the Exchange Web Services Windows Vista Gadget into an OSX widget. Exchange 2007 exposes functionality via Exchange Web Services, so why not take advantage of that to build something on the OSX platform?
Despite my deep dislike for JavaScript, I was interested in this project because I could finally see what it was like for developers on the other side. Kevin Marshall also finally got to use his G4 - nicknamed Quadzilla - as more than just an expensive foot rest.
The project is now available on CodePlex. I'll point out some things at the end of the post which caused us headaches during development, if you're interesting in contributing and helping out, please let me know.
DashCode
DashCode, part of the freely available Xcode suite, is a tool made specifically for building Dashboard widgets. DashCode works great for the purpose it was intended for: building widgets.
The keyboard shortcuts in DashCode are a little un-intuitive, so I found myself clicking around the IDE more than I would like. Otherwise, not much to complain about.
The great thing about DashCode is that it provides a native debugging environment for widgets. If you've built gadgets in Windows, you know you have to either deploy/run them to test, or trick them into running inside a web site.
However, in doing such a good job in enabling that, DashCode makes it a pain to integrate well with source control. A widget is simply a zip archive with a wdgtproj extension which DashCode knows how to open and edit.
However, no source control client is going to be intelligent enough to realize that you changed one of the files inside the wdgtproj file from within DashCode - they all treat the wdgtproj file as a folder. We ended up having to manually check out the files in source control, and then edit them in DashCode. Not a huge deal I guess, but required some extra care.
One thing that baffles me is the large number of tools included in Xcode. In Visual Studio, you have the idea of project templates to create different types of solutions. On the Mac side, there are a number of highly specific applications for certain types of projects.
Source Control
Teamprise puts out a great TFS client for OSX. You can try it out for free, or apply for a free licence if you're a contributor on a CodePlex project.
Widget
The widget mirrors the functionality of the original Vista gadget, allowing you to see the contents of your Inbox, Calendar, and Tasks.
You can click an item and open a flyout to see its details. From within the widget, you can also access a folder or item in Outlook Web Access.
When first starting up the widget, you have to provide some settings in order for it to connect to EWS on your Exchange Server. You can choose to specify the server manually, or let the widget use AutoDiscover to figure out the Url to EWS.
cURL / NTLM
We quickly found out that non-Microsoft implementations of XmlHTTPRequest don't implement NTLM. Since the widget is written in JavaScript, it effectively uses the XmlHTTPRequest provided in the Safari stack. This was a deal breaker, because a default Exchange 2007 installation is secured using NTLM.
One of our engineers discovered a utility called cURL that's available by default on OSX. cURL is a command-line utility originally intended to transfer files. However, with the right combination of parameters, we were able to use it to execute SOAP calls against EWS, and also use NTLM authentication.
What we ended up doing was using widget.system to execute cURL commands that posted our requests to EWS. You can use widget.system asynchronously, so we were able to implement callbacks that interpreted the cURL responses.
We of course lost out on a lot of goodness that comes with XmlHTTPRequest, e.g. a Status property to see the result of the HTTP request. We now have to parse a separation "authentication cURL request" for an HTTP error code.
Opportunities for Contribution
There are a couple of things which I would like to improve. If anybody is interested in contributing, please contact us through CodePlex or directly via the blog.
Use of cURL
There's gotta be a better way to do this. I read about the ability to write custom plug-ins for widgets, and in those you have full access to Apple's library - you're not limited by JavaScript. I've never written a line of Objective-C, so I didn't even know where to start with this.
Flyouts
The current flyout implementation is simply a div which we make visible after dynamically resizing the widget using widget.resizeBy. The funny thing about the current flyout is that the mouse scrollwheel only works when the cursor is in the scrollbar.
I really like how the Weather widget resizes elegantly, and would like to implement something similiar. This is something that Vista gadgets do a great job of providing natively.
Learnings
As far as how developers on the other side did things, it was interesting to get that experience. However, I always found myself wishing for some feature in Visual Studio that would have made my life easier in DashCode. On the other hand, the widget debugging experience was much better in DashCode.
Overall, the tools were decent, community content such as forums was hard to find, but Apple had some good developer documentation.
If you're not familiar with the OCSDKWrapper project on CodePlex, it's a wrapper that encapsulates the functionality of the Office Communicator 2007 SDK - allowing you to focus on building your application instead of dealing with the "plumbing" required to get the SDK wired up to Communicator.
Today I published Release 1.0.0.3 of the OCSDKWrapper which is now available for download.
This release includes some enhancements, some of them breaking changes, including:
-
Cleaner implementation of singleton design pattern that's used in the MOCAutomation class
-
All public methods are no longer static; they have to be accessed via the Instance property of MOCAutomation
-
Added a GetMyContacts method
I've also gotten a few requests to expose the underlying Communicator objects (IMessenger, IMessengerAdvanced, etc.) via an instance of MOCAutomation. That seems like a great idea if the developer needs to wire up some functionality that's not wrapped up in OCSDKWrapper.
This is really as simple as exposing these as public properties, I'm just working on some additional testing in case there are some side effects, e.g. if I did something like MOCAutomation.Instance.CommunicatorObjectProperty.SignOut().
Keep an eye on my blog or the CodePlex project for more updates as they become available.
I'm also looking for some contributors to put together another sample application that showcases some of the other functionality of the OCSDKWrapper, let me know if you're interested.