Thoughts on multi platform solutions

A couple days ago, I was at a JavaScript hacknight here in Toronto. I know the organizer (Dann) reasonably well, as i've been going to these events and other ones like it for a few years now.

I myself have been diving into cross platform solutions for a while, typically involving the JavaScript stack. I've messed around with nwjs a bit for desktop html5 games. I've used cordova for a couple projects at work to create android & iOS apps. I've written HTML5 games with various web libraries that are bundled in cocoonJS for the mobile app stores.

More recently for web content, I've been learning ReactJS. I have also watched the recent talks on React Native. All of these tools I find tend to serve two main purposes that the native frameworks do not:

  1. You can write the applications in a language you're familiar with
  2. Have more transferable code.

Obviously these vary from framework to framework. I'm sure we'll be using different components in iOS vs android environments with React Native.

I started talking with Dann about building native mac & windows apps with html+css+js and using NWJS, and how it almost feels wrong. Like we are clinging to the stack almost too much. No doubt it can be done, and can be done well. Atom is a good example of this. But I think there are limits.

Now let's say I wanted to build a markdown editor, as I'm picky and don't care much for the ones that exist already. The abstraction to native APIs that I would need would be writing to the file system. NodeJS makes this pretty simple, so an application like this is quite practical to build using a JavaScript stack.

What if I wanted to do something more complicated than that? What if I wanted to do a garage band type application? Where I'm able to record from an audio input device, split up a track, adjust volume levels, and export an mp3. This really steps up the difficulty. I'm sure it's doable with our beloved JS stack, but it's going to be much more practical using Cocoa APIs, and likewise the newer APIs in windows 8. Obviously that kind of application is much larger and vastly more complicated than the markdown editor. However, as I've worked on Cordova apps at work, it's easy to run into little problems here and there that an existing plugin doesn't solve. So you either end up writing your own plugin, or doing a bunch of hacky solutions JavaScript side, or you just leave it as a bad experience.

Over the last couple days, I have been doing some eesearch at work. The goal is to take 4 photos with an iOS app, and turn them into an animated gif. This gif would also require a client logo watermark on top, and it to be grayscaled. My tech lead found a pretty decent JavaScript plugin for putting images or video together to make a gif. However, the only way I could make it work with pure Javascript code, was to take 4 photos individually. Four calls to the camera plugin:

html_button.click ->
  launch camera plugin ->
    take photo ->
      confirm/retake ->

That was for each of the four pictures, so around 12 button presses. That's no good. My tech lead managed to find a tutorial on doing a custom camera plugin. We figured might as well try it for a couple hours, and see if it's practical. So I got started on it from the tutorial. I added some minor changes to it, as it had a couple bugs. Once I could take a single photo, I modified the Objective-C code a little bit to add an array of photo urls. Applied the resize & grayscale, then passed the array to the webview. This only took a few hours of work total. If I were to just pass the raw images to the web view, I'd have to then using multiple async calls to the file system. Resizing them with the canvas and grayscaling them would be so much more work, especially due to memory limitations of the webview. The simple & synchronous code on the iOS side made it this process much easier.

Now granted, if this project was going on android, windows phone and other devices, it becomes a bigger task to maintain the code base. But I felt quite pleased on the results when building a feature in the native side. At least this way, we can still leverage our design team on HTML & CSS. I know from now on that with Cordova, if we need more than the plugins provide us, there is a way.

I brought these kind of examples to Dann's attention. He responded, which I'm paraphrasing "It is quite silly that we have to use different languages for these platforms. Android runs Java, and iOS runs Objective C/Swift, this just adds friction for developers that want to build applications. It's these greivances that causes us to explore solutions that can work for each device. We create a common API that invokes the proper specific calls based on the platform."

He's absolute right about that. Frameworks like Titanium and Cordova do go for the write once, run everywher approach. However, with the speed that android & iOS move at, it's hard to keep up with all the native APIs. With Titanium, you can't write native components, you're stuffed if their API doesn't do something you need it to. This could very well apply to React Native.

That said, I do think it's worth it. I think with enough brains behind it all, and push for good practices, we can make these cross platform solutions work. Looking back in our history of hardware and cross platform support, very smart people worked on compilers that could work with various CPU architectures, so we could write things like C code on various computers. The web browser gives us a JavaScript run time that works fairly reliably across platforms. In the gaming world we have transpilers of HLSL to GLSL. Blizzard Entertainment has supported Mac & Windows games for years, signifying they must have tools for writing D3D code and OpenGL code with a native API.

But of course, we still have platform detection code. In game code I sometimes see #if windows, #if osx type calls. We will write different versions of shaders depending on the OpenGL version supported. Older code we wrote platform specific stuff, with the cordova app I wrote platform specific stuff. We all need to be smart on when we use certain tools. At the end of the day, use the right tools to deliver the experience you want to deliver.