Apple and Gaming

August 23rd, 2023

Lots has been written about Apple and gaming, but there's a point that I don't think has been made.

Games are units of entertainment, not apps.

What do I mean by this? Well, think of a movie, or a song. These are produced, usually by teams of people who work on them for some amount of time, until they're done. They release them, and then they move on to the next thing.

When new formats come along, some units of entertainment get upgraded to support the new format, but most don't.

I'm talking about things like the transition from 1080P to 4K, or music adding spatial audio.

The job of the media player is to play the media, no matter what. The Mac can play any old song from the oldest MP3 to the newest AAC. Apple has always been a little finicky about video formats but I believe any format Apple has actually supported can still be played in the newest players.

Apple as a company often takes a stance where they do what they believe is right and expect the world to adapt. Removing Flash in Safari, for example, was a significant hit to the web at the time, and thousands of sites just stopped working.

Games aren't apps. When a game is done, the team moves on. Sometimes old games get updates but most of the time there's just nobody in place to update a game and push a new build to the stores.

A rule that games that haven't been updated in 2 years are moved from the App Store is a pretty clear sign that Apple doesn't think of games as units of entertainment, they think of games as software.

Apple doesn't see it as their job to keep old games working, that's up to the developers. This attitude wouldn't be tolerated with old music or old movies, and it shouldn't be accepted for games.

SwiftUI: Solid filled background.

September 17th, 2019

Let's start with something simple.

Looking for a way to fill the screen with a solid colour?

The Spacer component expands to fill the available space. Add it at the root of the layout to simply fill the space with a colour.

    var body: some View {

If you want to layer things on top of it, you can use a ZStack. Put the Spacer as the first item in the ZStack so your ZStack expands to fill the screen.

struct WinView: View {
    @State private var animate = false

    var body: some View {
        ZStack() {
            Text("You win!")
                .font(Font.custom("Helvetica Bold", size: 200))


September 17th, 2019

Time to start blogging again. SwiftUI is heating things up.  Is this thing on?

Android + CircleCI + versionCode

December 9th, 2018

Automatically incrementing build numbers in CI is always a hassle. Here's a simple way of using a generated version number in your CI, based on the current time in 10 second intervals. This is based on this post by esplo but with the missing piece of how to read the version in the build.gradle.

Add this to your CircleCI .circleci/config.yml file:

- run:
name: Write versionCode to
command: |
U=$(expr $(date +%s) / 10) # increase by 1 in each 10 seconds
echo "versionCode=${U}" >> app/
cat app/

Add this to the top of your app's build.gradle:

def Properties versionProperties = new Properties()
versionProperties.load(new FileInputStream(file('')))

And then later in your app's build.gradle, to read the versionCode:

versionCode versionProperties['versionCode'].toInteger()

This way, the CircleCI build will write out versionCode to a file, for example:


And then the Gradle build will read it while building the app.

React Native or Electron: Why?

December 5th, 2018

Many developers hate Electron apps, and have a distaste for React Native apps. There are some good technical reasons for this. They're inelegant. Inefficient. Bloated, slow, pigs. That's the reputation.

But to the users? They're fine. They're good enough. I don't see users dropping Slack in favour of Skype because Skype is native. That's just now how users make these decisions.

But native is better right?  Big, smart, rich companies are choosing to build software using React Native and Electron. Why would they do this, given that the products will be, by some measures, sub-par?

It's not about the raw cost savings of using one code base. It's about the organization.

Software development is more than just developers. It's QA, HR, IT, CI, Design. UX.

Companies get addicted to their own branding. Most big, successful apps use their own look & feel, rather than adopting the platform conventions. Adobe apps don't look like Mac apps or Windows apps, they look like Adobe apps. Slack looks like Slack. Facebook looks like Facebook.  Word is going to come down that all of these apps need adopt the same look and feel on all platforms. In doing so, you're giving up the platform familiarity that users have with native apps.

There are 5 major platforms to build for: Mac, Windows, iOS, Android, and the web. If you're going to build a "native" app for each of these platforms, that's five times more design work to do. Five teams to manage. Five teams that you need to coordinate whenever you want to make a simple change.

If the 5 native apps could evolve on their own timeframe, it might be easier, but each platform has both internal and external factors that feed into development schedules. Releases need to be coordinated, feature sets coordinated, look & feel coordinated. 

Cross-platform development isn't about saving money on development; it's about coordinating development across all the platforms. Even if it cost *more* to build an Electron app than building separate native apps, I think for many companies it would be preferable. It's just easier to manage.

Sending RabbitMQ Message from JavaScript with async / await

November 22nd, 2018

I'm doing a lot of JavaScript development these days, and most of the example JS code I find on the web uses callbacks. I much prefer async/await, and sometimes the translation isn't obvious.  

Here's how to send a message using amqplib to RabbitMQ using async await.

The interesting bit here is the waitForConfirms method. You'd think you could await sendToQueue, and that would wait for the send to complete. However, the way amqpplib implements this, the call returns once the message is queued for sending. Without the waitForConfirms, the process.exit will run before the message is sent.

Building a Slack bot in Node

November 16th, 2018

I was looking into how to build a simple Slack bot. I ran across various bot kits and frameworks and whatnot, that seemed to really overcomplicate the issue. Went back to the Slack API and discovered that it's actually quite straightforward.

This particular code listens for messages in a private channel called 'dev'. Private channels are called 'Groups' in the Slack API.

The bot listens for messages, looks fo the text 'ping' and responds 'pong'.  The rest is up to you!

Local Siri

May 17th, 2018

Here's my WWDC prediction for 2018:

Siri will be significantly replaced with a new, on-device Siri.

A few attributes of this new Siri that would make it interesting, and give it a shot of coexisting in a world with Google Assistant, Alexa and Cortana:

  • Requests will run directly on your device. No more waiting for your voice to be uploaded and the response downloaded, no more spotty Siri when your network connectivity is down. This will significantly increase response time and reliability.
  • Siri will treat your devices as a single cloud, fetching information from other devices or sending a request to the device best suited to process it.

This goes a step beyond where Siri is today regarding your privacy, and from that perspective it's totally in sync with Apple's privacy stance. But does doing things locally mean worse results?

I don't think it has to. Some questions will require a network request, like asking how long it would take to drive somewhere, but if you're an Apple user who's all-in with iCloud, all your data is already on your device. Your documents, your calendars, messages, emails, can all be scanned by machine learning right on your device. Spotlight already does this for indexing.

So asking "What movies are playing nearby" will result in an internet request, but "Open the garage door" would not, since that can be completely handled inside your house on your local LAN. If you're out, it will send a message to one of your other devices that is at home, like the Apple TV or HomePod. This is how HomeKit works today.

This is what I'd like to see, but since I've never been right with my WWDC predictions, I'd suggest not getting your hopes up.

Formatting CVaListPointer

April 9th, 2018

So you're using libtiff in Swift, and need to implement the TIFFErrorHandler.

Or, for whatever reason, you have a CVaListPointer (the args parameter, below) and a format string, and you want to format. Here's how:

let errorHandler:TIFFErrorHandler = {
(moduleNamePtr, formatPtr, args) in
guard let formatPtr = formatPtr else {
// No format string - this is unexpected and there's
// not much we can do here, perhaps log that it happened.

// Convert the format pointer into a Swift String
let formatStr = String(cString:formatPtr)

// Create the output buffer
var buff = Data.init(count: 1024)

// Accessing the buffer's bytes...
buff.withUnsafeMutableBytes({ (ptr) -> () in
// Format into them
vsnprintf(ptr, 1024, formatStr.UTF8CString, args)

guard let formatted = String(data: buff, encoding: .utf8) else {
// This would only happen if the logging produced an invalid string,
// we don't have a string we can display

NSLog("TIFF error: \(formatted)")



The Amazon Web Services Platform

October 19th, 2017

I've been working with Amazon Web Services as part of a new job, and I was surprised to see how many rich services Amazon is offering under the AWS banner now.  


I made a point of looking at every one of them (as of October 2017) and reading enough about it to get what it's for. The scope of these services is incredible, and I get what the "serverless" trend is about now.  You can build and deploy complete application back ends in AWS, start to finish. No surprise to many, I'm sure, but last time I looked at AWS it was mostly storage and VMs.


Here's my cheat sheet.


Code Hosting


VMs in the cloud.

EC2 Container Service

Docker containers in the cloud.


Cheap, simple VMs in the cloud. Backed by EC2. Check out this StackOverflow post for some details.

Elastic Beanstalk

App hosting. You supply the your application code (Java, PHP, .NET, Node, Tomcat, Ruby, etc), and they run it on a managed server.


Function hosting. You write backend logic code in JS, C#, Java or Python, and it hooks up to an endpoint that you can call or trigger from other AWS activity. "Serverless".


Manages running large jobs in parallel Docker containers across many EC2 instances.

File Storage


Simple file storage with an HTTP API. Pay for the amount of storage and transfer you use.


Provides filesystem semantics on top of S3.


Slow, low-cost storage, for backups and archiving.

Storage Gateway

Software you run that acts as a local cache for your EFS data. Mount as iSCSI or as a share on your network.



Hosted SQL databases (hosting MySQL, PostgreSQL, or a number of others).


Amazon's own MongoDB style noSQL database.


Hosted redis / memcached compatible in-memory caching.

Amazon Redshift

"a fast, fully managed, petabyte-scale data warehouse solution"


Artificial Intelligence


Speech recognition and natural language understanding. Build a smart Slack bot.


Text to speech.


Imagine analysis and object detection.

Machine Learning

Machine learning. Upload models, run them on data.



Simple Queue Service

Message queueing service. Create queues, add messages to them, and have various things pull messages and act on them.

Simple Email Service

Send and receive email. SMTP gateway or API.

Simple Notification Service

Pub/Sub messaging, for delivering notifications to different parts of your application, and SMS notification service. (Those two don't seem that similar to me).


Developer Tools


Sort of a New Project wizard for creating projects that use Amazon services, in a large number of languages. Generates a Git repository and the provisions the services your project type needs.


Amazon does GitHub.


Amazon does continuous integration. 


Automated deployment of built applications to EC2 instances.


Visual workflow tool for orchestrating builds and deployments.


Log and trace collection and analysis for distributed applications.



Database Migration Service

Move your MySQL data into Amazon's Aurora SQL database.

Server Migration Service

Move your physical PC into an EC2 VM.


Move your local data into and out of Amazon by copying it to physical devices and shipping them around. 


That's the core stuff. I'm not going to list every other service, just the ones that I think might be of interest to app developers.



CDN. Make your content available quickly worldwide.


Amazon sells domains?


Monitoring for your AWS services.


Create templates for sets of services that you typically deploy together, with a visual editor for adding services and relationships.


Audit trail for things that happen across your AWS services.


Watches your AWS services and makes security, cost and other recommendations.


Automated security analysis of your services.

Certificate Manager

Free SSL certificates for your AWS-hosted services.


User account management services for your apps. Good blog post here.


Web application firewall.


Collect, process and analyze streaming data.


Online game server hosting, with game engine integration.

Mobile Hub

Helps you provision AWS services and integrate them into your mobile app. Not really a service itself.

Device Farm

Deploy your app to real physical devices for testing. "AWS Device Farm tests are run on real, non-rooted devices"


Spam your users with push notifications. I'm sorry, I mean "Engage Your Audience with Messaging Campaigns". Also includes app usage analytics.

Step Functions

High-level service that lets you create workflows by stringing together Lambda functions.


Another workflow service, which on the surface seems pretty similar to Step Functions. 


Stream desktop applications to a web browser.

Elastic Transcoder

Video format conversion.

API Gateway

Define your own external API to give to your developers as a front end for the services you've built in AWS.


There are also services under the AWS banner, like WorkDocs, WorkMail, WorkSpaces and Chime, that seem more like Office365 type user services than developer services.