Weekend Project: Alarm Jam
Weekend projects were a thing that my roommate and I coined back in the day when we first started going after internships and hackathon acceptances. Our goal was to make and publish a project over the span of a weekend. No hackathon, no class, no prizes. This is purely making for fun. The one requirement, however, is that these projects have to be done within a weekend from start to finish and they need to be complete (enough) to push into production as an MVP.
This one was an idea that I've had for a while now and I finally got around to building it. I've always wanted to be able to wake up to my own music. I hoped that when I bought my Amazon Echo, I'd be able to do this. There's always a song running in the back of my head and a morning alarm with that song is the perfect way to start out the day.
Building this as an Alexa Skill wasn't really feasible because Amazon doesn't really let us "ring" its devices. However, as I was experimenting, one way this was possible was using Spotify APIs. I had to utilize the Spotify Connect APIs and their service would handle playback on my Echo Devices as if I had sent a song from my computer.
Web View for Alarms
My initial approach was to build a website where users could log in and set alarms using a website. I wanted to monetize the creation of each alarm so that users would have to pay.
However, as with most web projects, monetization and authentication pose easy vulnerabilities, especially for a non-seasoned web developer like myself. It seemed that my basic ways of constructing payments and authentication would be too easy to exploit.
I got as far as to building a Mock UI, and then I pivoted to building a mobile app. From a UX perspective, alarms also seem like a better opportunity for mobile apps.
Building the Mobile App
My mobile tech stack was to use Xamarin Forms for this application. I know it well and I can iterate fast. The risk, as with most Xamarin Projects, is the surprise build errors that occur at random. Fortunately, I didn't face that with this project. Crisis averted.
Custom Authentication Flow
My users have to login with Spotify. This allows me to list playlists and also show their devices.
Usually, building an authentication flow for web apps is a pain point. I have a pretty popular Xamarin Auth Sample that I built a while ago. However, it required a complex workflow.
This was during a time I wasn't fully knowledgeable about the area. All I knew was how to write front-end code. Therefore, my code required implementing Custom Renderers.
After my recent experiences, I finally understand how callbacks and 3rd party authentication works. Hence, I was able to build my entire Spotify Login flow using just the Xamarin Forms
WebView, no custom renderers. I've been reading that it's not good practice to do so, but for the short term, it'll do.
One thing I am not satisfied with is that the WebView doesn't utilize the underlying native browser. Hence, a Facebook login doesn't pull in existing credentials or cookies. If I revisit my login page, I might go back and extend the Webview to utilize the native browser and write a tutorial. Overall, I am pretty happy with how it all worked out.
I took to the iOS Alarm App for inspiration. My goal was to replicate it. My final product ended up very similar. I ran into a challenge with Xamarin forms and binding to the SwitchCell that was a part of the Listview. Toggling the Switchcell did not return the context for the entire cell itself. However, I tackled this problem about a year ago with the UTD Makerspace App and adding to calendar buttons. I reviewed my past code and changed it to work for this case.
As far as setting alarms, it's just a matter of selecting a playlist and compatible devices. One thing I tried my best to do in this project was follow a strict MVC pattern. However, as usual, more UI tweaks meant me modifying the code. The majority of my code behind each XAML page was spent changing colors and adding subtle animations.
Crashes are Painful with Mobile
One thing I miss from web apps is that an entire app doesn't crash if something fails. However, that's not the case for mobile apps. Unhandled cases meant that the entire app failed. I ran into this problem especially with failed web requests and empty list sets.
However, I managed to overcome these problems with some rigorous manual testing. One thing I regret not learning when I had the chance back at Xamarin was a deeper dive into Calabash testing. Running automated UI testing is something that would help make my apps more safe to various conditions.
Serverless Alarm Handling
The back-end for this app was a challenge on its own. The programming difficulty was low, but architecting was harder than I had expected. However, AWS Lambda was up to the task. Cloudwatch Events allowed me to trigger my Lambda function every minute.
As far as app stucture, I don't even keep track of a database of users. All I have is one alarms table and a Lambda Function that runs every minute and fetches all of the alarms in that one minute. My Primary Partion Key was actually a mixture of the Alarm Time in UTC with the UserID I got from Spotify as the Secondary Key.
Spotify's refresh token for a user doesn't expire, so I'd use that to fetch a new access token when an alarm needed to be triggered and I played the necessary music. All in all, it was a fun setup.
I ran into some challenges with the Spotify API. Spotify Device IDs are not consistent. In fact, if my Alexa disconnected and reconnected to the internet, it would surface with a new ID. Therefore there was no guarantee my alarm would ring. To solve the problem, I built my own algorithm that utilized the Device name. Although the device name is also volatile, it doesn't fluctuate as often as the ID.
I ended up publishing my app to both Android and iOS, at least as an alpha rollout. An alarm app deserves high reliability, and this app needed to pass that.
I wanted to test it out before I published it. I wondered how other people would react to it. I reached out to various internet threads to get myself a group of testers!
I got a chance to use Fastlane for iOS deployment. I hope they're making millions because they really made my life easier. iOS certificates and code signing has always been a pain point. I still don't fully get it, but Fastlane made it so much easier during the publishing process.
On the other hand, Android publication was easy as pie. I released my app to Testflight and as an Alpha build for Android.
The response was encouraging, but my app reliability was not what I had hoped it would be in the sense of alarms going off consistently. More on this later.
When I first used Xamarin, all projects were preinstalled with Xamarin Insights, my personal favorite. After they were bought by Microsoft, Xamarin moved everyone to HockeyApp, a poor implementation of Insights that just didn't work out of the box. However, it seems that this time around, Xamarin encouraged us to move to Azure Mobile Center.
It was an easy installation. They built it around usage for Xamarin Forms. However, unlike Xamarin Insights, it required me to create two separate apps for Android and iOS in their dashboard.
Nonetheless, I got the information for downloads and crash reports just like I wanted. It also had a place for device testing and internal builds. I think with some more ironing, this is a good replacement for the original Xamarin Insights.
An Unreliable App
See, the problem with my app is that I hadn't forseen the poor reliability with Spotify APIs and device connection. If I publish this app, it would help people, but it would also make them hate me.
I don't want to be stamped as a poor developer because the reliability of the Spotify Device APIs are not fully flushed out yet. There is a pretty long issues list going on GitHu (Including one from myself)
I definitely put a lot of effort to making this a nice app. However, it's unfortunate to see that it might never come to light, althought there is a demand for it.
I don't want the lack of reliability, a factor I don't control, to be the reason this fails. I considered a fallback mechanism for failed alarms to utilize Twilio to send backup phone calls, but that would be too much overhead for a simple app. Until I can figure out a fix, this will be on my phone and only those who want to test it.
In Conclusion ...
Perhaps I'm a little disappointed with the app's end result. It solved my problem, but I'm bummed out that I couldn't solve it for anyone else. If I did, I don't think it would be up to their expected standards. I'll still reach out to those interested and follow up. Maybe there might be a little hope.
As far as Weekend Projects go, I think I'm going take a break from them. I'll write a reflection on that shortly!