<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Adam Bell</title><description>building / breaking things</description><link>https://blog.adambell.ca</link><language>en</language><lastBuildDate>Wed, 31 Dec 2025 14:03:41 -0500</lastBuildDate><pubDate>Wed, 31 Dec 2025 14:03:41 -0500</pubDate><ttl>250</ttl><atom:link href="https://blog.adambell.ca/rss.xml" rel="self" type="application/rss+xml"/><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20250116-McLarens-And-CarPlay</guid><title>McLarens and CarPlay</title><description></description><link>https://blog.adambell.ca/posts/20250116-McLarens-And-CarPlay</link><pubDate>Thu, 16 Jan 2025 22:05:00 -0500</pubDate><content:encoded><![CDATA[<p>For as long as I can remember, I've always been a fan of motorsport. Not the one where you turn left for 400 laps, I mean like the other racing: Formula 1, Le Mans, IndyCar, etc. The fact that there's teams dumping hundreds of millions of dollars of research into the sole goal of building the fastest car, is so pure and simple. The goal itself is simple, but the actual requirements to build something that's capable of going more than 225 miles per hour for 50+ laps straight and not fall apart is the hard part.</p><p>This, as well as playing copious amounts of Need for Speed, Forza, and Gran Turismo, are also the reason I’ve always been drawn to driving sports cars (particularly British, and mid-engine), and of those, those made by vendors that had a significant investment in motorsport. My first roadster was a 2006 Lotus Elise in Solar Yellow. It was so fun to zip around in. It was a super lightweight mid-engine convertible go kart, that also happened to be legal for the road. Built by a company with a legendary presence in Formula 1, it prioritized lightness and handling above all else, especially cost. The steering feel of that car was very direct (no power steering, just raw input from the road), and the interior had basically nothing above the bare essentials (except maybe climate controls, but nothing else, no carpets, not even power windows!).</p><p>It was with that, that I experienced some of my first track days racing with other Lotus owners in the Bay Area (many of which were extremely talented and humbled me into knowing just how much I was lacking in the experience department). However, being the Bay Area, it’s riddled with people who don't know how to drive (especially in the rain), and due to the Elise being basically a single fiberglass shell, it was actually really stressful to drive. Wicked fun, but if anyone ever tapped it faster than 2mph, it’d basically be a write off (since replacing the single clamshell cost more than the car itself).</p><img src="https://blog.adambell.ca/assets/elise.jpeg" alt="elise"/><p>It was for this reason that I eventually shifted to a Lotus Evora 400. The Evora lineup was meant to act as a compliment to the Elise and the Exige. Where the Elise and Exige were primarily focused on being as raw as possible, the Evora was more focused on being a useable road car… that could also put in some wicked lap times. That was actually one of the things that most surprised me when I first drove it, even though the interior was more comfortable, the handling and feel was never lost, in fact it felt just as good as my Elise. A slightly roomier cabin, but still a two seater with an even faster 0-60 (no convertible though, sadly). It was with the Evora that I learned almost everything I know nowadays about spirited driving and track days. Having put tons of miles into that car, driving it every day for ~5 years, I learned to appreciate all it had to offer (and all the extremely strange quirks that went with it). I still got to hang with the Lotus Club, that community really does have some of the nicest people I’ve ever met / learned from; nothing but pure passion and appreciation for motorsport. The amount of confidence you get driving these Lotus cars in corners (due to them being both mid-engine and having a fantastic center of gravity), just makes you want to push it more and more. From steadily improving my times at Thunderhill and Sonoma, to conquering the Corkscrew at Laguna Seca in the rain, I learned a lot about car control, braking, and improving entry / exit speeds.</p><img src="https://blog.adambell.ca/assets/evora.jpeg" alt="evora"/><h2>I'll Have What He's Having</h2><p>A couple summers ago though, my family ended up renting my dad a few laps in a Ferrari 458 as a gift for his birthday. Growing up he was always fixing cars in the garage (this is also probably a huge reason why I’m so into cars nowadays), so it felt fitting to let him experience something a little faster than the Volkswagens he would drive on the daily. Upon booking the rental for him, I also noticed a few other cars you could rent: a Porsche 911 GT3 RS, a Lamborghini Huracan, and a McLaren 720S.</p><p>It was at this point where I had the brilliant idea to also rent myself another mid-engine British race car.</p><p>McLaren has always been my number one car manufacturer (with Lotus as a close second), with another legendary presence in motorsport, especially Formula 1. Ever since the McLaren F1 launched at around the time I was born, it was <em>the</em> dream car I would always pick in every single racing game and still to this day is my all-time favourite car. This dream will still sadly probably stay a dream as buying one of the ~106 available globally nowadays will probably set you back at least 20 million dollars (I'm accepting donations if anyone's inclined!).</p><p>The McLaren F1 was built with the goal to build the best driving car ever, with no compromises. Turns out, their framework for building it worked so well that they ended up building arguably the <strong>best car of all time</strong> and held the record for the fastest road car for nearly 13 years straight (reaching a top speed of 240mph). The car was so good, in fact, that they slightly modified it, called it the McLaren F1 GTR, entered 4 of them into the 24 Hours of Le Mans, and then proceeded to win first, third, fourth, and fifth place at their first Le Mans ever. This sadly will probably never happen again as most, if not all, cars in that race nowadays are purpose-built for Le Mans vs. the McLaren F1, a road car being so good it could basically roll up to the start line unchanged. Speaking of wins in motorsport, they're also one of the only manufacturers ever to win the Motorsport Triple Crown (winning Le Mans, the Indianapolis 500, and the Monaco Grand Prix… with Ayrton Senna no less, one of the greatest Formula 1 drivers of all time). The livery of Senna's MP4/6 still lives rent-free in my head and I still cheer them on each year in Formula 1.</p><img src="https://blog.adambell.ca/assets/mclaren_technology_center.jpeg" alt="mclaren<em>technology</em>center"/><p>Seeing as though I would have an opportunity to drive one of McLaren's other cars and experience what goes into their DNA, I decided to rent the 720S.</p><p>Upon stepping into this fighter jet on wheels, I realized that it felt familiar. It gave the same feelings that my Lotus cars gave, a race car that was legal enough to be driven on the road. Off the initial line, I couldn't help but notice that this thing was basically like the NOS scenes you see in Fast in the Furious. You know, where the cars enter hyperspace and get 2x the horsepower when they turn on the NOS tanks, because, damn, it was fast. 0-60mph in like 2.8 seconds (for context, my Evora was almost twice as slow). Not only was it crazy fast, but it was also super stable, as long as you weren't oversteering in the corners and dumping the throttle, never once did I feel like I was losing control. Just like the Elise and Evora, the steering felt super direct and gave tons of information and feeling of the road. A lot of cars nowadays tend to dampen the steering and make it feel way lighter than it really is, but they nailed the steering feel in this car. The car also has this super cool hydraulic suspension system so it's always planted on the road and basically never runs out of grip. If you go over a bump and one wheel on one side of the car is raised, the other wheel on the other side is lowered to compensate and balance the car out. Those feelings sparked so much confidence that only after a couple laps I was flying past other Porsche 911 GT3 RSs as if they were Toyota Priuses. The instructor asked “Have you driven one of these before?”, of course my answer was no, I had only wished I did, but it just felt like a natural progression from the Lotus cars. Raw, direct feedback from steering, mid-engine weight distribution, yet literally 100x faster. It felt like a rocket ship glued to the ground. I remember parking the car and my dad asking "How was it?", I then replied "I need to get one of these".</p><h2>1 Year Later</h2><p>For the next year, I could not get the feeling of driving that 720S out of my head. It was one of the most remarkable driving experiences I've ever felt and was probably the closest I'll ever get to experiencing a fraction of what a Formula 1 car is like. I still loved driving my Evora, but this was something else entirely.</p><p>Later that year I decided to go visit McLaren of San Francisco "just to see" what they had.</p><p>A test drive and a week later, I then said goodbye to my Evora 400 and hello to a McLaren 720S Spider in McLaren Orange (one of the best colours IMO).</p><img src="https://blog.adambell.ca/assets/loma_mar.jpg" alt="loma<em>mar</em>drive"/><p>Now for context, in case it wasn't obvious, the Evora was my daily driver and as such this took its place. I've never really liked having multiple cars, and I find that the best way to learn everything about a car is to drive it everywhere (or at least wherever possible). This includes everything from getting groceries (the front trunk can actually hold <em>a lot</em>), to sitting in 280 traffic, <em>spirited</em> driving in the Santa Cruz mountains, and even ripping past turn 1 at Sonoma Raceway.</p><p>This car is absolutely incredible, and is something I'll be holding onto for a very long time. I'm excited to drive it every time I get to flip the door up vertically, step into the cockpit, press the big red Engine Start button, and hear the twin turbo 3.8L V8 rev up. The interior is sleek and simple, with a buttonless leather and carbon fiber steering wheel (no media controls, no HVAC, just a steering wheel). It's rare to find this nowadays, especially with so many other companies making their steering wheels have more buttons than an Xbox Controller, having terrible touch controls, or being stupid and choosing a yoke instead of a wheel entirely. It's also super comfortable, and has a massive front windshield with lots of visibility. Even the rear quarter panels are transparent so your blind spots are never blocked. All the other buttons are readily accessible to the driver on either sides of the cockpit all the while feeling super low to the ground (107mm off the ground to be specific). You can tell this was built and designed by people who love driving.</p><p>The dual clutch gearbox is so smooth and the way the exhaust sounds as it's cut when it upshifts around 5000 RPM sounds like it's straight out of a science fiction movie. At Laguna Seca I remember I had to carry so much speed through turns 5 and 6 with my Lotus cars (since they can lose a lot of speed trying to go uphill), but this car has so much torque it simply does not care. You could be at a standstill at the bottom of the hill, floor it, and in 5 seconds you'd be going 120mph. For all the extra power it has, it's still just as lightweight as my Evora was. I even got the opportunity to learn how to get it sliding sideways a bit through corners at the track to learn how their ESC (stability control) Dynamic setting works.</p><p>I have so much more to say about what it's like to drive and how much appreciation I have for all the engineers and designers that worked so hard to make this car exist, but today I want to focus on telling the story of my experience fixing one of it's smaller flaws…</p><p>It doesn't have CarPlay.</p><blockquote><p><strong>Editor's Note</strong>: huge first world problem, I'm fully aware.</p></blockquote><h2>So What Does It Have?</h2><p>The 720S was introduced at that awkward phase in car stereo technology times where Bluetooth was everywhere and CarPlay was just starting to exist. However, they sadly didn't seem to get around to implementing it, and it was only equipped with USB iPod support. So, I could use my iPhone for music, but that would require either using Bluetooth or USB.</p><p>There's two problems with this however:</p><ol><li>Bluetooth's bitrate maxes out at ~264kbps assuming we're doing AAC (which we are given it's iOS and the car doesn't seem to support anything like aptX or whatever). This is worse than a 320kbps MP3 file, and I could hear the compression artifacts, so this was immediately out of the question.</li><li>USB does provide the best quality, however that requires constantly plugging in the phone anytime I get in the car and I was already used to having wireless CarPlay in my Evora (which again, another huge first world problem, I'm aware).</li></ol><p>Now you might think: "Couldn't you just swap the stereo head unit like other cars?". I could, however for the 720S, McLaren built a fully custom bespoke one-off system that I can't quite swap. The system itself controls loads of proprietary things like tire settings, interior lighting, maps, sensors, track telemetry, even Variable Drift Control (you literally get a slider to adjust how much you want to drift!), and as such, nobody has really spent the time or effort to make an aftermarket swap.</p><img src="https://blog.adambell.ca/assets/mclaren_infotainment_off.jpeg" alt="mclaren<em>infotainment</em>off"/><blockquote><p><strong>Editor's Note</strong>: It turns out the newly released 750S now does have CarPlay, but that also didn't feel like a cost-effective solution.</p></blockquote><p>The whole setup is actually pretty sweet, the gauge cluster can flip down to show you just your shift lights when you're in track mode and you get an audible cue when's the optimal time to shift gears.</p><div align="center">
<video controls width="80%">
  <source src="https://blog.adambell.ca/assets/mclaren_folding_dash_optimized.mp4" />
</video>
</div><p>So anyways, this custom head unit does a ton of stuff, surely there's something we could do with it, right?</p><h2>Jailbreaking the Car?</h2><p>Upon further inspection, the infotainment system seems to have been developed by JVC / Kenwood (which lines up properly with this <a href="https://www.jvckenwood.com/en/press/2017/05/press_170518.html">press coverage</a> denoting JVC did a custom system for McLaren). Upon using it though, I figured that it was running a variant of Android due to the distinct way it handles scrolling at the edges of any given screen (you get that glow effect instead of rubber banding like you would on iOS or Windows Phone 🪦). Now considering that this car was unveiled in 2017 and the electrical systems were developed around then (or earlier, technology moves slow in the car space), it's probably not running Lollipop or Marshmallow (since those were bleeding-edge at the time and this is likely an embedded system). I'd bet probably something like Android 3.0, surely we can just jailbreak it right?</p><p>Turns out people have already done this with the McLaren 650S and below, apparently adb is running if you connect your car to the iPod USB port. They sadly patched this for the 720S. In addition, after trying some other things, I realized it wasn't actually Android, but a different embedded Linux system entirely (long story… probably for a future blog post maybe)… so I guess I'll just take the dash apart and try to jailbreak it myself?</p><p>Yeah… no. Given how fun of a project that would be to try, I'd really rather not accidentally brick my car. I don't think the dealership would be cool with me bringing it in for service to somehow reflash the infotainment system with a proper image because I managed to get it to not turn on anymore. Loads of Android devices are trivial to hack since they all have fastboot and you can just restore it if you mess something up, but I'm gonna wager that nobody has dumped the software off this system nor has McLaren hosted bootloader images on GitHub. It also seems extremely cumbersome to try and take all of the dash apart, so… yeah, no.</p><p>Feeling rather bummed that his avenue was not gonna happen, I started thinking about what I was trying to optimize for: enable wireless playback of my music in my car, with media controls, and at the highest bitrate I can (or at least better than Bluetooth). It was at this point that I remembered that wireless CarPlay operates by first setting up a WiFi network over Bluetooth and then streams CarPlay via AirPlay over WiFi to the car. So maybe I could make my own "CarPlay"? What if somehow I added AirPlay to my car? I saw projects where people ripped up old AirPort Expresses, but I needed to run off a cigarette lighter and not have something nuke the small racecar-optimized battery, so I settled on a Raspberry Pi. They only require 5v at like 5 or 6 watts or so, so the energy usage would be mostly the same as having my iPhone plugged in.</p><p>Upon setting up a lite version of Raspbian, I started looking for projects that implemented an open source AirPlay receiver server and I came across <a href="https://github.com/mikebrady/shairport-sync">shairport-sync</a>. Turns out Mike Brady did all the hard work and already thought of this <a href="https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md">use case</a> (thank you Mike!). Once setup, you'll have a Raspberry Pi that broadcasts a WiFi network and an AirPlay server that'll output whatever it receives over 3.5mm / AUX. My car did in fact have a 3.5mm input jack, however initial testing resulted in a ton of electrical noise (static, clicking, etc.) coming out the speakers. Turns out the way my car was wired up <em>really</em> didn't like the electrical interference that was created when you hooked a Raspberry Pi up to the cigarette lighter or iPod USB port and then played that same device over 3.5mm back into the car. After spending a couple days trying to debug and troubleshoot with some ground-loop inhibitors and various cables, I still couldn't get a clean signal (maybe it was still interference, maybe just the Pi's DAC, no idea), so I started over.</p><h2>iPod USB</h2><p>It turns out the Raspberry Pi's USB-C port supports USB OTG, meaning the Raspberry Pi could dynamically switch that USB port from being a host port (e.g. hosting a keyboard) to a device port (e.g. act as a device that the car could host).</p><p>I then started looking through tons of stuff to see how I could somehow "emulate" an iPod via my Raspberry Pi. I looked through RockBox source code, thought about virtual machines, anything really, but I eventually stumbled across <a href="https://github.com/oandrew/ipod-gadget">ipod-gadget</a>.</p><p>This project was <strong>perfect</strong>:</p><blockquote><p>ipod-gadget simulates an iPod USB device to stream digital audio to iPod compatible devices/docks. It speaks iAP (iPod Accessory Protocol) and starts an audio streaming session.</p></blockquote><p>So assuming this works, I could plug the Raspberry Pi into the car and have it <em>think</em> it's an iPod. I had doubts it would work without issue as it had tons of patches for specific stereo head units, but I set it up just to see what would happen. I configured Shairport Sync to use <code>hw:iPodUSB</code> as this was the ALSA audio device that it exposes, went to the car, plugged it in and…</p><h2>UNSUPPORTED DEVICE</h2><p>:(</p><p>So either the car didn't recognize the "iPod" or the "iPod" didn't recognize the car. The ipod-gadget project involves two parts:</p><ol><li>A Linux character device (/dev/iap0`) you send stuff to (to send over USB)</li><li>A client app (<code>ipod</code>) written in Go that talks to said device.</li></ol><p>Upon trying to inspect the logs output by the <code>ipod</code> server binary, it didn't produce anything meaningful. I then did a sanity check with my home stereo to see if it would do anything, and it worked perfectly.</p><p>I brought it back to the car and tried again just to see, and no matter what I tried, it would constantly fail to connect. I then re-checked the logs with the <code>ipod</code> server running on the Pi with more verbosity and then I noticed there were a bunch of packets that would fail to parse and would be dropped. So I patched that bit of code to just spit out raw bytes to see if I could get anything.</p><p>A few things seemed to stream out and then it would just stop (here, <code>&gt;&gt;&gt;</code> means incoming, as in car -&gt; Raspberry Pi).</p><pre data-language="bash" class="hljs"><code>&gt;&gt;&gt; 0xFF 0x55 0x02 0x00 0xEE 0x10 0x00 0x00

&gt;&gt;&gt; 0xFF 0x55 0x02 0x00 0xEE 0x10 0x00 0x00

&gt;&gt;&gt; 0xFF 0x55 0x02 0x00 0xEE 0x10 0x00 0x00
</code></pre><p>I took what I saw, and dumped it into the GitHub search box.</p><p>🤷‍♂️ <img src="https://blog.adambell.ca/assets/iap2_search_result1.png" alt="iap2-search-result1"/></p><p>I wish it would've been that easy. Trying a few permutations finally lead me somewhere...</p><img src="https://blog.adambell.ca/assets/iap2_search_result2.png" alt="iap2-search-result2"/><p>This search result was just pure luck, but it was super helpful. Notice how the first result is Rockbox, which is an open source media player implementation that runs on old iPods. As such it also implements the same protocol as the <a href="https://github.com/oandrew/ipod-gadget">ipod-gadget</a> (iAP). However, it isn't referencing that byte sequence we're looking for, the project below it <a href="https://github.com/wiomoc/iap2/">wiomoc/iap2</a> <strong>is</strong>.</p><p>Upon reading wiomoc's extremely helpful <a href="https://wiomoc.de/misc/posts/mfi_iap.html">blog post</a> I now knew what I was dealing with.</p><p>My car's stereo didn't implement iAP1… but iAP2 and has "iPod" listed in the car's infotainment as in "iPod Accessory Protocol"… not necessarily supporting "iPod devices". So having read through most of Christoph's (wiomoc) post (thank you for writing this!), I got the idea to just send back the same sequence of bytes the car was sending me. Apparently this is a way for a device to acknowledge that it talks iAP2.</p><p>I modified the go ipod project and upon doing this, I had thousands of bytes streaming on the screen to parse through (here, <code>&lt;&lt;&lt;</code> means outgoing, as in Raspberry Pi -&gt; car):</p><pre data-language="bash" class="hljs"><code>&gt;&gt;&gt; 0xFF 0x55 0x02 0x00 0xEE 0x10 0x00 0x00

&lt;&lt;&lt; 0xFF 0x55 0x02 0x00 0xEE 0x10 0x00 0x00

&gt;&gt;&gt; 0xFF 0x5A 0x00 0x1D 0x80 0x74 0x00 0x00 
    0x96 0x01 0x05 0x10 0x00 0x0F 0xA0 0x00 
    0x49 0x1E 0x05 0x0A 0x00 0x01 0x0C 0x01 
    0x01 0x0B 0x02 0x01 0xA8 0x00 0x00 0x00 ...
</code></pre><p>Neat.</p><p>Now what?</p><p>Upon reading more of the blog post and <code>iap2</code> project, I realized I was probably going to have to do a lot of stuff on my own. Apple's iAP2 protocol documentation is <strong>only</strong> available to members of Apple's MFI program, and to qualify for the program, you basically have to be an accessory maker (e.g. Belkin) that makes or ships thousands of MFI devices. As such, I basically only had open source projects to go off, and thankfully the <code>iap2</code> project was enough to get me started.</p><h2>Let's Emulate an iPhone in Swift</h2><p>The idea, in theory, was what if I could just take my Raspberry Pi and convert it into an "iPhone", but only do enough of the parts that iAP2 cares about to play audio.</p><p>To start, I used the <code>ipod-gadget</code> project again in order to reuse that character device <code>/dev/iap0</code> over which I could send and receive bytes. This project already has the correct USB HID descriptors and whatnot setup to mask as an iPhone, so it saved a lot of time doing the basics.</p><p>Next I started a Swift command line utility project that I could compile and run on Linux (since I was running this on a Raspberry Pi).</p><blockquote><p><strong>Sidenote</strong>: Swift on Linux is pretty great nowadays. You can just <em>build and run</em> on Linux. You can't use Xcode to debug on Linux, but it's pretty trivial to debug remotely with Visual Studio and the various extensions.</p></blockquote><p>After that, I setup the basis for reading and writing bytes to/from the character device using a <code>DispatchSource</code> both for input and output:</p><pre data-language="swift" class="hljs"><code><span class="hljs-keyword">self</span>.io = <span class="hljs-keyword">try</span>! <span class="hljs-type">FileDescriptor</span>.<span class="hljs-keyword">open</span>(<span class="hljs-string">"/dev/iap0"</span>, .readWrite, permissions: .ownerReadWriteExecute)
<span class="hljs-keyword">self</span>.buffer = <span class="hljs-type">UnsafeMutableRawBufferPointer</span>.allocate(byteCount: <span class="hljs-number">1024</span>, alignment: <span class="hljs-type">MemoryLayout</span>&lt;<span class="hljs-type">UInt8</span>&gt;.alignment)

<span class="hljs-keyword">self</span>.queue = <span class="hljs-type">DispatchQueue</span>(label: <span class="hljs-string">"ca.adambell.HIDReader"</span>, qos: .userInitiated, autoreleaseFrequency: .workItem)
<span class="hljs-keyword">self</span>.source = <span class="hljs-type">DispatchSource</span>.makeReadSource(fileDescriptor: io.rawValue, queue: queue)
source!.setEventHandler { [<span class="hljs-keyword">weak</span> <span class="hljs-keyword">self</span>] <span class="hljs-keyword">in</span>
    <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> <span class="hljs-keyword">self</span> <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }
    <span class="hljs-keyword">do</span> {
        <span class="hljs-keyword">let</span> bytesRead = <span class="hljs-keyword">try</span> io.read(into: buffer)
        
        ipod.parseBytes(bytesRead)
    } <span class="hljs-keyword">catch</span> {
				<span class="hljs-comment">// handle errors</span>
    }
}
</code></pre><p>For output, all I had to do was encode stuff as little-endian bytes and write them to the character device:</p><pre data-language="swift" class="hljs"><code><span class="hljs-keyword">self</span>.queue = <span class="hljs-type">DispatchQueue</span>(label: <span class="hljs-string">"ca.adambell.HIDWriter"</span>, qos: .userInitiated, autoreleaseFrequency: .workItem)
<span class="hljs-keyword">self</span>.source = <span class="hljs-type">DispatchSource</span>.makeWriteSource(fileDescriptor: io.rawValue, queue: queue)
source.setEventHandler { [<span class="hljs-keyword">weak</span> <span class="hljs-keyword">self</span>] <span class="hljs-keyword">in</span>
    <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> <span class="hljs-keyword">self</span> <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }

    <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> report = reportQueue.popFirst() {
        _write(report)
    }

    <span class="hljs-keyword">if</span> reportQueue.isEmpty {
        source.suspend()
        <span class="hljs-keyword">self</span>.writing = <span class="hljs-literal">false</span>
    }
}

<span class="hljs-keyword">let</span> bytesToSend = [<span class="hljs-number">0xff</span>, <span class="hljs-number">0x55</span>, <span class="hljs-number">0x02</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0xee</span>, <span class="hljs-number">0x10</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x00</span>]

queue.async { [<span class="hljs-keyword">weak</span> <span class="hljs-keyword">self</span>] <span class="hljs-keyword">in</span>
    <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> <span class="hljs-keyword">self</span> <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }

    reportQueue.append(bytesToSend)
		source.resume()
}
</code></pre><p>Originally I tried using Swift 6 actors / <code>async</code> / <code>await</code>, however I had to switch back to plain old Dispatch as it turns out that <code>Task</code> and <code>DispatchSource</code> really don't play nicely together yet (see: FB14132060) :(</p><p>So once I got the project up and running I began map out what exactly I wanted to get working:</p><ol><li>Music Playback (obviously)</li><li>Track Metadata (hopefully cover art?)</li><li>Media Controls (<em>if</em> I can make it work)</li></ol><p>The infotainment system in the car supports a bunch of stuff like browsing your Music library and accessing playlists, but I didn't care about much of that since I was just going to be using AirPlay. I could control all that from my iPhone mounted to the dash.</p><p>Continuing on, I got back to the same spot I was at with reading bytes with the original <code>ipod</code> client (however, at this point it was all in Swift!):</p><pre data-language="bash" class="hljs"><code>&gt;&gt;&gt; 0xFF 0x55 0x02 0x00 0xEE 0x10 0x00 0x00

&lt;&lt;&lt; 0xFF 0x55 0x02 0x00 0xEE 0x10 0x00 0x00

&gt;&gt;&gt; 0xFF 0x5A 0x00 0x1D 0x80 0x74 0x00 0x00 
    0x96 0x01 0x05 0x10 0x00 0x0F 0xA0 0x00 
    0x49 0x1E 0x05 0x0A 0x00 0x01 0x0C 0x01 
    0x01 0x0B 0x02 0x01 0xA8 0x00 0x00 0x00 ...
</code></pre><p>Referencing wiomoc's blog post once more, I noticed a small detail:</p><blockquote><p>Therefore it first sends a message to the accessory requesting the certificate of the Authentication Coprocessor. The accessory retrieves this certificate from the Coprocessor and send it in a response message. The iPhone checks if this certificate is signed by Apple. Upon successful validation, the iPhone generates a challenge and transmits it to the accessory. [...]</p></blockquote><blockquote><p>After this authentication procedure is completed, the accessory sends some identification information, like name, serial number, supported transports or offered EA protocols to the iPhone. After an acknowledgement from the iPhone, the iAP2 Connection is fully established.</p></blockquote><p>Crap.</p><p>I thought the whole project was probably screwed at this point since I had no way of getting ahold of said iPhone Authentication Coprocessor. Without said coprocessor, I'd never be able to authenticate a session. It's probably baked into the iPhone's system on a chip and I had absolutely no means of taking it out or repurposing it.</p><p>However, then I realized, I'm not communicating with an iPhone… I'm <em>spoofing</em> one and talking to the infotainment system.</p><p>In order to get an accessory to do anything, you need to have the accessory "identify" itself. Once that starts, it'll then authenticate itself with an iPhone and will use the onboard authentication coprocessor to validate that the MFI accessory is "legit".</p><p>In my case, since I'm the super totally legit iPhone™ that's "authenticating" the infotainment system, I can just send a thumbs up to whatever it says.</p><p><strong>Infotainment System</strong>: "Hey I'm a licensed MFI car stereo: here's a signed challenge showing I'm legit"</p><p></p><p><strong>Me (a totally legit iPhone)</strong>:</p><pre data-language="swift" class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">checkChallenge</span><span class="hljs-params">()</span></span> { 
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
}
</code></pre><p>"… Sure! You're good 👍"</p><p>I then loosely used wiomoc's code as a point of reference and built out the initial session setup and communication channels necessary to get me to the identification phase. Once I implemented this, gone were the "Unsupported Device" errors that my car was showing me. I still had tons of bytes being thrown at me that I had no idea what they were, but it was connected.</p><p>For fun I tried AirPlay-ing what I was listening to at the current time (I remember it vividly, it was "A Walk in the Woods" by Marty O'Donnell from the Halo: Combat Evolved Soundtrack)… and it worked!! It turns out all my car cared about was an initial iAP2 session and then it'd just play whatever was coming over USB by any UAC (USB Audio Class) device!</p><img src="https://blog.adambell.ca/assets/walk_in_the_woods.png" alt="walk-in-the-woods"/><blockquote><p><strong>Editor's Note</strong>: <a href="https://marioaguzman.github.io/quicktune/">QuickTune</a> is fantastic. Great work Mario!</p></blockquote><p>I'd AirPlay my iPhone to the Raspberry Pi, it'd create an iAP2 session and then just dump whatever was coming over AirPlay to the car's infotainment system.</p><p>This crazy wild combination of devices ACTUALLY WORKED:</p><p><code>iPhone → [shairport-sync] → [ipod (swift tool)] → McLaren Infotainment System</code></p><p align="center"><iframe width="315" height="560" src="https://www.youtube.com/embed/UNGmwV-Lo2s"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen></iframe></p><p>So here's where we were at:</p><ol><li><s>Music Playback (obviously)</s></li><li><strong>Track Metadata</strong> (hopefully cover art?)</li><li>Media Controls (<em>if</em> I can make it work)</li></ol><p>Now, since I do a lot of track days, I also have McLaren P1 race bucket seats installed in my car. They're fantastic for hugging your body as you take corners super quickly, but absolutely horrible for posture / hacking on things in the car. My neck and back started to hurt after a few of nights of hacking on things in the driver's seat.</p><img src="https://blog.adambell.ca/assets/p1_car_seats.jpeg" alt="p1<em>car</em>seats"/><p>In addition, it turns out that my code was originally so bad, I would sometimes send invalid bytes to the car… and the car's infotainment system would just lockup or crash / restart. So I'd have to shut the car off, restart it (in accessory mode, no need to power on the engine), and keep it hooked up to a trickle charger to ensure the battery didn't die as the alternator isn't running without the engine on.</p><p>For the sake of my spine, I really needed to figure out an alternative to continue working on this project.</p><p>Knowing how software works in most of the tech industry, if a company has functional software, chances are they won't rewrite it for other things (if it works, why rewrite it?). Heck, apparently some companies still rely on WebObjects running on a Mac Mini somewhere under someone's desk. Chances are, if JVC / Kenwood built an infotainment system for McLaren, they probably borrowed a lot of code they already had for other stereos (their implementation of iAP2). In this case, I assumed I could just buy another Kenwood stereo from Best Buy and hack on that instead. If I got things working with that, it should work with my car with little modification. As such, I bought a super cheap single DIN stereo and stuck it on my desk. I had to hard wire some power lines and hook up some speaker cables (it was extremely sketch), but eventually I had a "similar" car stereo on my desk I could mess with.</p><img src="https://blog.adambell.ca/assets/car_stereo_on_desk.jpeg" alt="car<em>stereo</em>on_desk"/><p>I plugged in the current WIP I had with the Raspberry Pi and worked out of the box! Shared code!</p><img src="https://blog.adambell.ca/assets/car_stereo_stop.jpeg" alt="car<em>stereo</em>stop"/><p>Sadly, progress on this project <em>swiftly</em><a href="#mclarens-and-carplay-note1">¹</a> halted as wiomoc's code didn't really cover any sort of media / metadata iAP2 stuff.</p><p>That's where I had to get a bit more crafty…</p><h2>Hanging Out With HID</h2><p>When reverse engineering APIs for the web, you typically setup some sort of <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">man-in-the-middle attack</a> and read the incoming or outgoing requests. A lot of people default to things like <a href="https://mitmproxy.org">mitmproxy</a>, <a href="https://proxyman.io">Proxyman</a>, <a href="https://www.wireshark.org">Wireshark</a>, or <a href="https://www.charlesproxy.com">Charles Proxy</a>. Now, normally if this were over the web, that's what I'd be pulling out. However, this is all over USB, and I didn't know the format I was working with, so what I sorta needed was a USB Proxy for HID (which is what all the messages are sent over).</p><p>Turns out, there's a project that does just that: <a href="https://github.com/AristoChen/usb-proxy">usb-proxy</a>. It worked great initially, but often times would crash due to the volume of traffic going over the cable.</p><p>Eventually I found an alternative: a pretty sweet project called <a href="https://cynthion.readthedocs.io">Cynthion</a> that does what <code>usb-proxy</code> does, but in hardware!!</p><img src="https://blog.adambell.ca/assets/cynthion.jpg" alt="cynthion"/><p>This thing is wicked cool. You put it in the middle of a USB Device (iPhone) and a USB Host (Stereo) and it basically just spits out all the bytes that goes over the USB cable so you can analyze it. It comes with a tool called <a href="https://github.com/greatscottgadgets/packetry">Packetry</a> that allows you to analyze each HID frame that comes in:</p><img src="https://blog.adambell.ca/assets/packetry.png" alt="packetry"/><p>Notice anything familiar? ^_^</p><p>From making the other iAP2 messages work (e.g. identification), I knew the general gist for what things looked like (there's a header, some size bytes, a checksum, blah blah, and a payload), so I just needed an easy way to find the payloads I wanted to replicate. Most of the iAP2 messages seemed to start with <code>0xFF 0x5A</code> so that made it a lot easier to narrow things down.</p><p>Media controls were actually trivial to figure out, so I figured those out first. All I did was run my <code>ipod</code> app and have it spit out any incoming frames / messages it didn't understand. In this case, I would just watch the console as I tapped various media buttons on the stereo (Play, Pause, Next, Previous, etc.). I'd spam tap a button (e.g. Play / Pause) and look for similar packets. I'd then diff them to try to build up an <code>enum</code>:</p><pre data-language="swift" class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">MediaControl</span>: <span class="hljs-title">UInt8</span> </span>{
    <span class="hljs-keyword">case</span> playPause = <span class="hljs-number">0x02</span>
    <span class="hljs-keyword">case</span> next = <span class="hljs-number">0x04</span>
    <span class="hljs-keyword">case</span> previous = <span class="hljs-number">0x08</span>
    ...
}
</code></pre><p>No idea if this is actually the spec, but in my case, I never actually needed to send these <em>to</em> the car, so I didn't care about figuring out the format. I just needed a means to watch for these packets from the car -&gt; Raspberry Pi, get the media button pressed, and then I'd control Shairport Sync myself using the dbus client it exposes:</p><pre data-language="swift" class="hljs"><code><span class="hljs-comment">// Shell is implemented elsewhere, but it just uses Process / Pipe from Foundation</span>
<span class="hljs-keyword">if</span> control == .playPause {
  <span class="hljs-keyword">try</span> <span class="hljs-type">Shell</span>.command(<span class="hljs-string">"dbus-send --system --type=method_call --dest=org.gnome.ShairportSync '/org/gnome/ShairportSync' org.gnome.ShairportSync.RemoteControl.Play"</span>)
}
</code></pre><ol><li><s>Music Playback (obviously)</s></li><li><strong>Track Metadata</strong> (hopefully cover art?)</li><li><s>Media Controls (if I can make it work)</s></li></ol><p>Metadata was a lot more involved. What I was really looking for was a way to display Title, Artist, and Album (and album artwork if possible!) onto the infotainment screen. While this wasn't strictly necessary, I do like being able to see chapter titles from podcasts or songs being streamed on Apple Music. As such, I needed to find the correct offsets / structures to send as USB packets.</p><p>I generated a test track and uploaded it to my iPhone with the following:</p><ul><li>Title: <code>TITLE_HERE</code></li><li>Artist: <code>ARTIS_HERE</code></li><li>Album: <code>ALBUM_HERE</code></li><li>Album Art: A simple 512x512 opaque red png.</li></ul><blockquote><p><strong>Note</strong>: <code>ARTIS_HERE</code> is an intentional typo as I wanted a consistent length for the strings sent (10 bytes, aka <code>0xa</code>) to make it easier to find their patterns.</p></blockquote><p>I played this test track on my iPhone when hooked up to the stereo (through Cynthion) and then I found the following bytes in the pcap file:</p><img src="https://blog.adambell.ca/assets/metadata_packet.png" alt="metadata_packet"/><p>Notice the highlighted area. Before that you have <code>0xe</code> as the length, but the length of the strings I was sending was <code>0xa</code>. It turns out that the length also includes the bytes that specify the size (2 bytes) as well as 2 other bytes that indicate the type of information supplied (<code>0x00, 0x01</code>, aka Title), so removing those 4 bytes, we get 10 bytes: <code>0xe - 0x04 == 10</code></p><p>Initially I wasn't getting anywhere, but it was far easier to iterate on since I could just keep trying new formatted packets to see if anything would appear on the stereo screen. Still having no luck, I tried replaying the same packets dumped via Packetry but still, nothing would appear on the stereo's display. Eventually I realized that there was consistently another packet sent before the track info (more on that later), I didn't really care what it was, but once I sent it before the metadata packet, it then started to display my strings! Sometimes it would crash due to messing up the sizes sent or other orderings, but eventually I got that working just fine.</p><img src="https://blog.adambell.ca/assets/metadata_showing_on_display.jpeg" alt="metadata<em>on</em>display"/><blockquote><p><strong>Editor's Note</strong>: Not shown here were the multiple days of trial and error and sheer frustration that comes out of throwing random stuff at a black box until something happens. There were many times where I nearly gave up because of brittle issues that cascaded and broke other things that weren’t even related. Sometimes things would work, sometimes trying the same thing again would fail and crash the unit.</p></blockquote><p>The only thing that was remaining was figuring out how to send cover art. This actually ended up being the hardest part since I had to figure out how to do the File Transfer Session stuff. It turns out you need to specify an identifier for the image to be sent alongside the track metadata (in that "other" packet mentioned above), and then send the image separately in a different session. I got pretty close a few times trying to figure it out on my own, but then I stumbled upon some "questionable" GitHub repos that gave me a lot more hints and then I eventually got artwork displaying. In short: you setup an identifier, send it along with the track info, send the image bytes in packets, and then tell it you're done on the last packet.</p><ol><li><s>Music Playback (obviously)</s></li><li><s>Track Metadata (hopefully cover art?)</s></li><li><s>Media Controls (if I can make it work)</s></li></ol><h2>Shairport Sync → Stereo</h2><p>The next part was finding a way to get the currently played track's metadata to show on the stereo. I needed to get it <em>out</em> of Shairport Sync and pass it to the stereo (i.e. getting metadata out of the AirPlay session). For that, you can build Shairport Sync with metadata and cover art enabled. Once built, it’ll publish metadata info at <code>/tmp/shairport-sync-metadata</code>. So then I wrote a Swift parser to pull out the various metadata items I was looking for and would pass them to the stereo anytime they changed.</p><p>Putting it altogether, and skipping ahead in time, I eventually had everything that I wanted!</p><p>When I plugged the Raspberry Pi into the car, it'd trick it into thinking it was an iPhone, the car would accept USB audio, and I'd just connect my iPhone over AirPlay to the Raspberry Pi to play my music. AirPlay 1 specifically runs as lossless 44100Hz, meaning I had bit-perfect CD quality audio running wirelessly in my 720S! What's even more wild is stuff like phone calls and Siri just worked perfectly out of the box. The McLaren allows me to disable the media / audio protocols for connected Bluetooth devices and only allows the hands free protocol for sound input (i.e. microphone). I could then simultaneously connect it to AirPlay for sound output! :D</p><p>It worked perfectly and even things like chapter titles / artwork from Overcast worked!</p><img src="https://blog.adambell.ca/assets/buy_your_car_an_iphone.jpeg" alt="buy<em>your</em>car<em>an</em>iphone"/><h2>Adding a Bit More "CarPlay"</h2><p>The nice thing about wireless CarPlay is it's very hands-free. You get in the car, drive, and it's already connected. So to complete my "CarPlay", I needed a means to automate its connection.</p><p>Shortcuts to the rescue!</p><p>Sadly, iOS doesn't have a shortcut to have your iOS device connect to a specific WiFi network (because reasons)… so to have it automatically connect I configured the WiFi network my Raspberry Pi broadcasts to be the highest priority for the iPhone to connect to it. In doing so it would take precedence over my home WiFi and you can set this up via macOS and then it syncs over iCloud back to the iPhone. I then made a Shortcuts automation to automatically run when connected to the car's Bluetooth:</p><ol><li>Disable WiFi</li><li>Wait a few seconds (hardcoded to roughly the boot time of the Raspberry Pi)</li><li>Re-enable WiFi (connecting to the in-car WiFi since it has a higher priority)</li></ol><img src="https://blog.adambell.ca/assets/wifi_on_off_shortcut.png" alt="shortcut<em>wifi</em>on_off"/><p>I then ran a second Shortcut automation when I connected to the in-car WiFi:</p><ol><li>Enable the "McLaren" focus mode on my iPhone, which populates my home screen with <a href="https://apps.apple.com/us/app/albums-music-shortcuts/id1602404960">Albums</a> widgets for my favourites<a href="#mclarens-and-carplay-note2">²</a></li><li>Wait a few seconds to ensure the AirPlay network is fully ready</li><li>Set the sound output to my in-car AirPlay network</li></ol><img src="https://blog.adambell.ca/assets/mclaren_focus_airplay_shortcut.png" alt="shortcut<em>wifi</em>on_off"/><p>I'd then do the reverse (and pause media if playing when it ever disconnected from my in-car WiFi) to make it as seamless as possible and to ensure that music wouldn't keep playing after I parked the car.</p><h2>Oops, I Broke It</h2><p>One thing that didn't originally occur to me was that anytime I shut off the car… I was just cutting power to the Raspberry Pi without shutting it down safely. At one point the Raspberry Pi stopped booting entirely so I had to re-image it and set it up again.</p><p>This time I optimized the boot time to be as fast as possible (getting it down to roughly ~7s). I looked through the startup path using <code>systemd-analyze blame</code> and just disabled anything that wasn't related to audio or networking. I then enabled a read-only filesystem so the filesystem would just be running as a tmpfs in RAM so no more changes could be made to the Raspberry Pi and would prevent further issues.</p><p>I also had another issue where some songs would have odd distortion with certain frequencies. This took so much trial and error, but eventually I discovered that if I forced Shairport Sync's format to be <code>S16_LE</code> (signed 16bit little endian), the problem went away.</p><p>Lastly, I then cloned the SD Card to disk and saved it in case I ever broke something again (so I could just re-image it easily).</p><h2>More Broken Stuff!!</h2><p>Now of course, all this worked perfectly for a few months, and then iOS 17.4 came out and <a href="https://github.com/mikebrady/shairport-sync/issues/1822">broke my media controls</a>. -_-</p><p>It turns out that Apple removed needed parameters to control the AirPlay session (notable <code>DACP-ID</code> and <code>Active-Remote</code>), and without those there wasn't a way for me to do things like play, pause, or skip tracks.</p><p>sigh.</p><p>Well since my project was already a pile of hacks that magically worked together, I figured I could just hack it up even more. Bluetooth devices can support AVRCP (Audio/Video Remote Control Profile)… so I just made my Raspberry Pi into a fake AVRCP device and had it automatically connect to my iPhone. I'd pair my iPhone via Bluetooth additionally to the Raspberry Pi, and then the Raspberry Pi could then Play / Pause / Skip tracks on my iPhone using AVRCP (acting as a Media Player Remote Control, think Media Keys on a keyboard):</p><pre data-language="bash" class="hljs"><code>dbus-send --system --<span class="hljs-built_in">print</span>-reply --dest=org.bluez /org/bluez/hci0/dev_00_11_22_33_44_55 org.bluez.MediaControl1.Play
</code></pre><p>Instead of sending dbus commands to Shairport Sync, I'd send them to a bluez client. I had to do some clowntown Bluetooth configuration in Linux that I don't really remember, but eventually I got things working. It definitely did not include putting a while loop in <code>/etc/rc.local</code> to spam connect to the iPhone over Bluetooth on boot. It was hideous, but it worked.</p><p>I then made another backup image of the disk so I never had to debug Bluetooth stuff ever again.</p><h2>End Notes</h2><p>Putting all this together has left me with probably one of the most <s>hacked up piles of software that somehow works together</s> advanced audio stacks in any McLaren 720S. I now have a car that'll automatically connect to my phone and play music in its highest available quality (as in available to native implementations on iOS… here's hoping one day AirPlay will support higher quality like 48000Hz). It's not exactly "CarPlay", but it's close enough. I need to give a huge shoutout to Mike Brady, Andrew Onyshchuk, and Christoph Walcher for all the work they did on their respective projects. I wouldn't have been able to do this without them.</p><p>This has been an incredible learning opportunity for me, exploring so many things up and down the stack: USB, Linux kernel drivers, HID transports, Bluetooth, reverse-engineering embedded systems and protocols, low level audio formats / sequences, the list goes on and on. This also allowed me to appreciate all the complexities that go into building reliable car infotainment systems. In the end this truly was a fun yet ridiculously over-engineered project to solve a simple problem. That being said, I've now got a pretty sweet computer running in my car all the time, so I've got tons of other ideas for other projects to do in the future (track day logging??). Not only that, but I have Swift powering part of my car's audio stack!</p><p>Sometimes the best solutions are those held together with digital duct tape.</p><img src="https://blog.adambell.ca/assets/mclaren_track_day.jpeg" alt="mclaren<em>track</em>day"/><p id="mclarens-and-carplay-note1">¹: 🥁</p><p id="mclarens-and-carplay-note2">²: This massive project was actually a catalyst for building <a href="https://apps.apple.com/us/app/albums-music-shortcuts/id1602404960">Albums</a>. Initially, I wanted a consistent way to get to my favourite music without needing to navigate small tap targets on various streaming apps, but then it ended up becoming a full-fledged app that I'm super proud of and love using all the time! :D</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20230127-Blog-Upgrade-Time</guid><title>Blog Upgrade Time (aka Blogging in Swift Part 4)</title><description></description><link>https://blog.adambell.ca/posts/20230127-Blog-Upgrade-Time</link><pubDate>Fri, 27 Jan 2023 11:00:00 -0500</pubDate><content:encoded><![CDATA[<p>Well, that was easy!</p><p>I <a href="https://mastodon.social/@b3ll/109758892359428583">posted</a> about contemplating on upgrading my blog to use something like <a href="https://github.com/johnsundell/Publish">Publish</a> so I could spend less time maintaining my blog and more time writing for it. In short, my old blog was a server I wrote myself which would take markdown files (blog posts) and dynamically convert them to HTML and serve them, this was kinda ineffecient, but it was a great learning experience. The previous blog was built atop <a href="https://blog.adambell.ca/posts/20200402-Blogging-in-Swift-%2528Part-3%2529-%2528aka-Vapor-time%2529">Vapor</a>, but with every Swift release / update to Vapor, I'd find myself rebuilding it on the server, which took forever on the tiny little server hosting this website. I had looked at using docker to containerize the whole thing, but:</p><ol><li>I had no idea what I was doing.</li><li>Cross compiling docker for x86_64 (which is what my server is) on an arm64 laptop (my M1 Max MacBook Pro) was actually slower than building on the server directly, so I ditched that idea.</li><li>I still don't even know what a kubernetes is (does anybody really?).</li></ol><p>I saw loads of people talking very highly of <a href="https://github.com/johnsundell/Publish">Publish</a>, so I figured I'd give it a shot. Publish does much of the same, it takes markdown files (blog posts) and prints them out to statically served HTML files, which should be a lot less overhead too (than the less efficient route I had before).</p><p>Turns out it was pretty trivial:</p><ol><li>I took the markdown files I had from my previous blog, and copied them over to Publish.</li><li>I updated some of the markdown files' links to adapt to the new static site directory that Publish uses (i.e. instead of <code>blog.adambell.ca/date-post-title</code> with Publish it's <code>blog.adambell.ca/posts/date-post-title</code>).</li><li>… yeah that's pretty much it.</li></ol><p>Building and running the site is really simple. Just build and run from within Xcode (running is what prints out the website to the <code>Output</code> directory), and then use <code>publish run</code> from within the project directory to startup a server to view it locally at <code>http://localhost:8000</code>.</p><p>Once done, it looked a whole lot like <a href="https://www.swiftbysundell.com">SwiftBySundell</a>. 😂</p><img src="https://blog.adambell.ca/assets/swift-by-b3ll.png" alt="swift-by-b3ll"/><p>This was still more than enough to get myself started however. Publish uses themes to configure how it looks, and the built-in one is just very basic. I ended up porting all the old css from the old blog to Publish's layout and that worked just fine.</p><p>The next part was getting syntax highlighting working. I was originally using <code>pygments.js</code>, but seeing as how much Publish focuses on being a lightweight static site generation platform, I figured I'd try using whatever it had built-in. Publish features <a href="https://github.com/JohnSundell/Splash">Splash</a>, a lightweight syntax highlighter, however when I used that, it would crash due to some recursion issue with how much whitespace I was using, so I'll file an issue for that <em>soon</em>. To get around this, I ended up opting for using <code>highlight.js</code>, but with a Publish <a href="https://github.com/JohnSundell/Publish/blob/master/Documentation/HowTo/SyntaxHighlighting/using-highlight-js.md">plugin</a> so it'll statically run <code>highlight.js</code> at build time and applies styles to <code>code</code> blocks. This means the site will look the exact same with or without javascript support enabled.</p><p>Lastly was adapting some of my other pages to work correctly, notably the Talks page and the Archive page.</p><p>I have my talks modeled from my previous blog as a struct like this:</p><pre data-language="swift" class="hljs"><code><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Talk</span>: <span class="hljs-title">Codable</span> </span>{
    <span class="hljs-keyword">let</span> date: <span class="hljs-type">Date</span>

    <span class="hljs-keyword">let</span> title: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> venue: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> <span class="hljs-type">URL</span>: <span class="hljs-type">String</span>

    <span class="hljs-keyword">let</span> postDateString: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> localizedDateString: <span class="hljs-type">String</span>

    <span class="hljs-keyword">init</span>(title: <span class="hljs-type">String</span>, venue: <span class="hljs-type">String</span>, dateString: <span class="hljs-type">String</span>, <span class="hljs-type">URL</span>: <span class="hljs-type">String</span>) {
        <span class="hljs-keyword">self</span>.title = title
        <span class="hljs-keyword">self</span>.venue = venue
        <span class="hljs-keyword">self</span>.postDateString = dateString
        <span class="hljs-keyword">self</span>.date = postDateFormatter.date(from: dateString)!
        <span class="hljs-keyword">self</span>.localizedDateString = localizedDateFormatter.string(from: date)
        <span class="hljs-keyword">self</span>.<span class="hljs-type">URL</span> = <span class="hljs-type">URL</span>
    }
}
</code></pre><p>I couldn't quite figure out how to adapt these entirely to Publish's <code>Item</code> protocol since I'm still learning how this all works, so I ended up just sorta doing my own thing for rendering that section of the site. I then added <code>talks</code> as a section to my site, and created an empty <code>talks</code> folder so that Publish would generate things for that section:</p><pre data-language="swift" class="hljs"><code><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Blog</span>: <span class="hljs-title">Website</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">SectionID</span>: <span class="hljs-title">String</span>, <span class="hljs-title">WebsiteSectionID</span> </span>{
        <span class="hljs-keyword">case</span> posts
        <span class="hljs-keyword">case</span> talks
        <span class="hljs-keyword">case</span> archive
    }

<span class="hljs-comment">/* ... */</span>
</code></pre><p>So I created an array of all of my talk recordings:</p><pre data-language="swift" class="hljs"><code><span class="hljs-keyword">public</span> <span class="hljs-keyword">let</span> <span class="hljs-type">AllTalks</span>: [<span class="hljs-type">Talk</span>] = [
    <span class="hljs-type">Talk</span>(title: <span class="hljs-string">"Crafting Responsive and Playful Interfaces"</span>, 
         venue: <span class="hljs-string">"NSSpain"</span>, 
         dateString: <span class="hljs-string">"20220916"</span>, 
         <span class="hljs-type">URL</span>: <span class="hljs-string">"https://vimeo.com/751571352/3330bd3af4"</span>),
    <span class="hljs-comment">/* ... */</span>
]
</code></pre><p>And within my implementation of the <code>HTMLFactory</code> protocol for the custom theme, I setup the section like so:</p><pre data-language="swift" class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeSectionHTML</span><span class="hljs-params">(<span class="hljs-keyword">for</span> section: Section&lt;Site&gt;, context: PublishingContext&lt;Site&gt;)</span></span> <span class="hljs-keyword">throws</span> -&gt; <span class="hljs-type">HTML</span> {
    <span class="hljs-keyword">switch</span> section.id {
        <span class="hljs-keyword">case</span> .talks:
            <span class="hljs-keyword">return</span> <span class="hljs-type">HTML</span>(
                .lang(context.site.language),
                .head(<span class="hljs-keyword">for</span>: section, on: context.site),
                .body {
                    <span class="hljs-type">SiteHeader</span>(context: context, selectedSelectionID: section.id)
                    <span class="hljs-type">Wrapper</span> {
                        <span class="hljs-type">H1</span>(section.title)
                        <span class="hljs-type">List</span>(<span class="hljs-type">AllTalks</span>) { talk <span class="hljs-keyword">in</span>
                            <span class="hljs-type">Div</span> {
                                <span class="hljs-type">Link</span>(<span class="hljs-string">"\(talk.title) - \(talk.venue)"</span>, url: talk.<span class="hljs-type">URL</span>)
                                <span class="hljs-type">Text</span>(talk.localizedDateString)
                            }
                            <span class="hljs-class">.<span class="hljs-keyword">class</span>("<span class="hljs-title">talk</span>-<span class="hljs-title">list</span>-<span class="hljs-title">item</span>")
                        }
                        .<span class="hljs-title">id</span>("<span class="hljs-title">talk</span>-<span class="hljs-title">list</span>")
                    }
                    <span class="hljs-title">SiteFooter</span>()
                }
            )
        /* ... */
    }
}</span>
</code></pre><p>You'll notice here that I'm iterating over all the talks and creating a <code>List</code> (which effectively maps to a <code>&lt;ul&gt;</code> in HTML, with each item inside being a <code>&lt;div&gt;</code> wrapped within a <code>&lt;li&gt;</code>). It's pretty easy to assign classes or ids to things as needed so you can easily style with CSS. For sections where I didn't want rendered via this method, I just returned an empty <code>HTML()</code>. One example is the home page which is created via <code>makeIndexHTML(for:context:)</code>.</p><p>Putting it altogether, it worked great!</p><img src="https://blog.adambell.ca/assets/talks-rendered.png" alt="final rendering of talks page"/><p><strong>Note</strong>: Publish has its own item management and protocols which make a lot of this more straightforward / less manual, but I didn't quite figure all that out yet, feedback is welcome!</p><p>The Archive page way was done in mostly the same way.</p><p>The SwiftUI-like syntax is powered by <a href="https://github.com/JohnSundell/Plot">Plot</a> and is <em>really</em> nice. I had some small hiccups trying to understand how to the syntax worked at first, but the raw HTML escape hatches were great for prototyping how things worked when I was stuck. Compared to using Vapor's leaf, I really enjoyed having the type-safety that Plot enforces, it was a lot easier dealing with getting the Swift compiler to be happy vs. debugging why the templating language wouldn't quite do what I wanted.</p><p>I also realized that the RSS configuration for my old site was kinda broken, and Publish sorta just fixed all this magically! It generates an RSS feed by default for all the posts you have, which is also another thing I don't need to keep track of.</p><p>Deploying it was also really simple. Syncing the <code>Output</code> directory to an nginx server and adding some rewrite rules to map the old blog URLs to the newer format was added to preserve other articles linking back here and avoid link rot.</p><p>All in all, it was maybe a few hours of work to port the whole thing over. I even left some room for some more fun to overhaul the navigation and add some springs for fun! :)</p><p>This should be the last post here about writing blogs in Swift (hopefully). I have some more stuff in store, especially about animations!</p><p>Hopefully now that there's less maintenance needed for this blog, I can write a whole lot more! The lightweight nature of Publish and its simplicity has already made writing this post way more fun! It's also far faster to render (with javascript no longer necessary for syntax highlighting) and acts as a normal statically hosted website (no dynamic swift server code).</p><p>Thanks <a href="https://mastodon.social/@johnsundell">John</a> for making Publish! :)</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20200402-Blogging-in-Swift-(Part-3)-(aka-Vapor-time)</guid><title>Blogging in Swift (Part 3) (aka Vapor time)</title><description></description><link>https://blog.adambell.ca/posts/20200402-Blogging-in-Swift-(Part-3)-(aka-Vapor-time)</link><pubDate>Thu, 2 Apr 2020 00:00:00 -0400</pubDate><content:encoded><![CDATA[<img src="https://blog.adambell.ca/assets/Vaporwave-lol.jpeg" alt="https://daily.bandcamp.com/features/vaporwave-and-hip-hop"/><h2>Introduction</h2><p>This post follows where my server-side Swift Kitura adventures <a href="https://blog.adambell.ca/posts/20190529-Blogging-in-Swift-%2528Part-2%2529">left off</a>.</p><p>Some sad news came about when it was announced that Kitura was <a href="https://forums.swift.org/t/december-12th-2019/31735">winding down</a>, and I realized that, since I built my blog using Kitura, I should probably find an alternative with a more stable future.</p><p>I peeked around and <a href="https://vapor.codes/">Vapor</a> caught my eye.</p><h2>Vapor</h2><p>Quoting their GitHub:</p><blockquote><p>"Vapor is a web framework for Swift. It provides a beautifully expressive and easy to use foundation for your next website, API, or cloud project."</p></blockquote><p>It's one of the most popular server-side Swift frameworks nowadays, powered by Swift NIO, and powers some pretty cool apps (like <a href="https://scribbletogether.com">Scribble</a>: an app that let's you share whiteboard space remotely!).</p><p>It even has some pretty nice integrations with things like <code>SQLite</code> and has some pretty nice ORM stuff with their Fluent library. For my blog it's pretty basic, and doesn't really use any of this though.</p><h2>Fixing Routes</h2><p>The first thing I had to do was setup a new vapor app using their <a href="https://docs.vapor.codes/3.0/install/macos/">guide</a>.</p><p><strong>Note:</strong> <em>As of writing this, Vapor 4 is in the RC stages so it may very well be available by the time you're reading this.</em></p><p>The rest of it was relatively painless and just required me to restructure some of my routing.</p><p>What once looked like this in Kitura:</p><pre data-language="swift" class="hljs"><code>app.router.<span class="hljs-keyword">get</span>(<span class="hljs-string">"/"</span>) { request, response, next <span class="hljs-keyword">in</span>
  <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> recentPosts = getAllPosts(atPath: blogFileServer.absoluteRootPath, limit: <span class="hljs-number">6</span>) <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }

  <span class="hljs-keyword">do</span> {
    <span class="hljs-keyword">try</span> response.render(<span class="hljs-string">"blog-home.stencil"</span>, context: [ <span class="hljs-string">"posts"</span>: recentPosts.<span class="hljs-built_in">map</span> { $<span class="hljs-number">0</span>.dictionaryRepresentation } ])
    response.status(.<span class="hljs-type">OK</span>)
  } <span class="hljs-keyword">catch</span> <span class="hljs-keyword">let</span> error {
    response.send(json: [<span class="hljs-string">"Error"</span>: error.localizedDescription])
  }

  next()
}
</code></pre><p>Became this in Vapor:</p><pre data-language="swift" class="hljs"><code>router.<span class="hljs-keyword">get</span>(<span class="hljs-string">"/"</span>) { request -&gt; <span class="hljs-type">Future</span>&lt;<span class="hljs-type">View</span>&gt; <span class="hljs-keyword">in</span>
  <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> recentPosts = getAllPosts(atPath: rootBlogPath, limit: <span class="hljs-number">6</span>) <span class="hljs-keyword">else</span> { <span class="hljs-keyword">throw</span> <span class="hljs-type">Abort</span>(.notFound, reason: <span class="hljs-string">""</span>) }

  <span class="hljs-keyword">return</span> <span class="hljs-keyword">try</span> request.view().render(<span class="hljs-string">"blog-home"</span>, [<span class="hljs-string">"posts"</span>: recentPosts.<span class="hljs-built_in">map</span> { $<span class="hljs-number">0</span>.dictionaryRepresentation }])
}
</code></pre><p>What's nice is the API changes slimmed things down to a significantly more simple way of defining the root page for my blog.</p><p>You'll notice that requests return <code>Future</code>s of <code>View</code>s, which will resolve at some point in the future (reminds me a lot of <a href="https://hacklang.org">Hack</a>!).</p><p>Also, this gets rid of the <code>next()</code> invocations littered about when using Kitura, which I never personally really understood that well.</p><h2>Stencil to Leaf</h2><p>The next thing I had to port over were my stencil definitions. Kitura uses Leaf, which is another way of defining HTML templates that Vapor can populate.</p><p>They were basically the same, except for a few syntactic changes, namely the use of <code>#(something)</code> instead of <code>{{ something }}</code>.</p><p>You can check out the documentation for Leaf <a href="https://docs.vapor.codes/3.0/leaf/getting-started/">here</a>.</p><p>Kitura:</p><pre data-language="html" class="hljs"><code><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {% for post in posts %}
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
        {{ post.title }}
      <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      {% endfor %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre><p>Vapor:</p><pre data-language="html" class="hljs"><code><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      #for(post in posts) {
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
        #(post.title)
      <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      }
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre><h2>Conclusion</h2><p>For my case, switching over was really simple and felt like a relatively painless API migration. What's kinda neat too is, at least in my case, Vapor is noticeably more stable when running my blog. It hasn't gone down once since porting over (which would happen every month or so with Kitura).</p><p>In addition, compile times seem to have been halved, although I'm not sure if this is just tangential to Swift improvements or not.</p><p>Vapor seems great to me! I'm sad to see Kitura go, but hopefully this one stays around!</p><p>Give it a go if you're interested!</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20190724-Visualizing-Xcode's-View-Debugger</guid><title>Visualizing Xcode's View Debugger</title><description></description><link>https://blog.adambell.ca/posts/20190724-Visualizing-Xcode's-View-Debugger</link><pubDate>Wed, 24 Jul 2019 00:00:00 -0400</pubDate><content:encoded><![CDATA[<img src="https://blog.adambell.ca/assets/Xcode.jpg" alt="https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html"/><p>A couple days ago I noticed a really weird bug, images that had been used as templates would occasionally draw darker or lighter (rather than the color originally chosen). I thought it was just some weird duplicate layer ontop of another layer that would lead to the icon being darker / lighter.</p><p>I tried using Xcode's View Debugger, but it just wouldn't work at all and would error out with:</p><pre data-language="bash" class="hljs"><code>Assertion failed: ([layer isKindOfClass:[self class]]), <span class="hljs-keyword">function</span> -[CALayer _initWithReference:], file /BuildRoot/Library/Caches/com.apple.xbs/Sources/QuartzCore/QuartzCore-697.24.4.2/LayerKit/api/CALayer.mm, line 1947.
</code></pre><p>Somehow we had a <code>CALayer</code> which… wasn't a <code>CALayer</code>? Seeing as though Mojave has been having some super broken <code>CALayer</code> stuff <a href="https://www.omnigroup.com/blog/compatibility-warning-macos-mojave-10.14.4">recently</a>, I assumed it might've been a similar issue. Perhaps having too many layers was also corrupting the rendering of images?</p><p>It turns out, the original bug in question is actually an AppKit bug, but this bug lead me down a path of understanding how Xcode's View Debugger works.</p><h2>Debugging a… Debugger</h2><p>I figured I could just put a breakpoint on <code>-[CALayer initWithReference:]</code>, but sadly that breakpoint was never hit. There were potentially a few reasons from this:</p><ol><li>There's some out of process that handles Xcode's View Debugger.</li><li>This <code>-[CALayer initWithReference:]</code> is being invoked inside Xcode's process.</li><li>LLDB breakpoints don't work with Xcode's View Debugger.</li></ol><p>Cutting this writeup short, there's no XPC process we need to worry about (thankfully), and manually attaching LLDB to Xcode and trying to break on that function didn't work either. Turns out, LLDB doesn't work when you're trying to set a breakpoint during Xcode's loading of the View Debugger, so we need to get a bit more creative…</p><p>After starting the View Debugger, we can use <code>image list</code> to print out all the currently loaded libraries into the app being debugged:</p><pre data-language="bash" class="hljs"><code>(lldb) image list
...
[  1] F217F7F8-A795-3109-B77F-B1E2277F3E3B 0x0000000103fea000 /usr/lib/dyld
...
[298] BD43F13C-7F88-301D-A860-77EE5F6CBBE4 0x00000001042bc000 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Debugger/libViewDebuggerSupport.dylib  
...
</code></pre><p><code>libViewDebuggerSupport.dylib</code> looks interesting.</p><p>It turns out, Xcode will dynamically inject that dylib into the running application and call some special methods on it in order to get info on how the application's view hierarchy works. This is very similar to how <a href="https://revealapp.com">Reveal</a> works (albeit sadly that app doesn't work for debugging AppKit apps…).</p><h2>Finding Callsites</h2><p>Now that we know what binary is being loaded, we need to find out how it's actually starting this view debugging code. We can use static analysis and decompilation to figure this out.</p><p><a href="https://www.hopperapp.com">Hopper</a> is a fantastic tool for taking apart binaries, and it's something I always find myself coming back to. The way it works? Simply hand it an executable, and it will disassemble the executable, showing the innerworkings of what it does.</p><p>Opening that dylib up into Hopper, and searching for "viewdebugger" will give us lots of results for methods on the class <code>DBGViewDebuggerSupport</code>. Trawling through those results we'll eventually find <code>[DBGViewDebuggerSupport fetchViewHierarchy]</code>. Now this seems to be the main-ish method that's called to kickstart things, so we'll see what it does. We're trying to find where the layers are referenced so we'll see what happens with the sublayer hierarchies. Eventually we'll see something like</p><pre data-language="objectivec" class="hljs"><code>var_170 = [r14 _collectSubviewInfoForView:r13 encodeLayers:rcx];
</code></pre><p>This is shown in the decompiled code, <code>$r14</code> and <code>$r13</code> are registers in the CPU, which hold references to objects (kinda). Navigating inside that method, we'll eventually find the magic function that we seem to be breaking: <code>CAEncodeLayerTree(CALayer *layer)</code> which is inside <code>QuartzCore.framework</code>.</p><h2>Calling Private Functions</h2><p>Now, whilst it'd be easy to just invoke that function from LLDB, our breakpoint still won't be hit (since you can't break on things being invoked from LLDB), so we need to hardcode a way of invoking it. <code>CAEncodeLayerTree</code> also is private API, and has no header definition, so we'll need to use something else… something like <code>dlopen</code> and <code>dlsym</code> should help! <code>dlopen</code> will open / load a library into the current process and return a pointer to the address where it starts in memory, and <code>dlsym</code> will lookup the pointer to the function itself so we can manually call it:</p><pre data-language="objectivec" class="hljs"><code><span class="hljs-meta">#import <span class="hljs-meta-string">&lt;dlfcn.h&gt;</span></span>

<span class="hljs-keyword">void</span> *quartzCore = dlopen(<span class="hljs-string">"/System/Library/Frameworks/QuartzCore.framework/QuartzCore"</span>, RTLD_NOW|RTLD_GLOBAL);
<span class="hljs-keyword">void</span>(* <span class="hljs-built_in">CAEncodeLayerTree</span>)(<span class="hljs-built_in">CALayer</span> *) = (<span class="hljs-keyword">void</span> (*)(<span class="hljs-built_in">CALayer</span> *))dlsym(quartzCore, <span class="hljs-string">"CAEncodeLayerTree"</span>);
<span class="hljs-built_in">CAEncodeLayerTree</span>(view.layer);
</code></pre><p>I assigned this to a double click, but you can invoke it however you like.</p><p>Finally, to figure out the weird layer that's breaking things, we can use LLDB's conditional breakpoints:</p><pre data-language="bash" class="hljs"><code>(lldb) b -[CALayer _initWithReference:]
Breakpoint 5: <span class="hljs-built_in">where</span> = QuartzCore`-[CALayer _initWithReference:], address = 0x00007fff496ba037
(lldb) breakpoint <span class="hljs-built_in">set</span> --name <span class="hljs-string">"-[CALayer _initWithReference:]"</span> --condition <span class="hljs-string">'([$arg3 isKindOfClass:[$arg1 class]] == 0)'</span>
</code></pre><p>Here we're setting a conditional breakpoint on <code>-[CALayer _initWithReference:]</code> emulating the assert that was failing previously. Here, <code>$arg3</code> is the argument passed to <code>-initWithReference:</code> and <code>$arg1</code> is the object the method is being invoked on (aka <code>self</code> when you've hit the breakpoint). This is using aliases for registers that'd be used when calling Objective-C methods. For more details on how these "pseudo" registers work, check out <a href="https://www.natashatherobot.com/xcode-debugging-trick/">@natashatherobot's post</a>, and if you're super interested, <a href="http://www.arigrant.com/blog/2014/2/18/chisels-print-invocation-command">this post</a> goes into lots of details.</p><p>Finally, invoking this will allow us to finally find our view that's breaking things. Once the breakpoint is hit, we can just invoke <code>po $arg3</code> to see what object is breaking things.</p><h2>Closing Notes</h2><p>In my case, I was incorrectly configuring a <code>CAGradientLayer</code>'s delegate incorrectly. Fixing that resolved the issue.</p><p>Sometimes the best approach to fixing bugs is to, well, debug a debugger. It's pretty dense, and reverse engineering opaque technologies isn't talked about that much nowadays, so I figured I'd post more broadly about how I go about researching / investigating the internals of various things.</p><p>Hope you found this post helpful and If you've got any questions, feel free to <a href="https://twitter.com/b3ll">message me</a>!</p><blockquote><p>PS: <a href="https://twitter.com/indragie">@indragie</a> made an amazing open source project that aims to replicate Xcode's View Debugger / Reveal and it's pretty awesome. Check it out <a href="https://github.com/indragiek/InAppViewDebugger">here</a>!</p></blockquote>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20190529-Blogging-in-Swift-(Part-2)</guid><title>Blogging in Swift (Part 2)</title><description></description><link>https://blog.adambell.ca/posts/20190529-Blogging-in-Swift-(Part-2)</link><pubDate>Wed, 29 May 2019 00:00:00 -0400</pubDate><content:encoded><![CDATA[<h2>Introduction</h2><p>This post follows where the <a href="https://blog.adambell.ca/posts/20190417-Blogging-in-Swift">first part</a> left off.</p><p>Now that you've written a blog, or whatever you'd like as part of server-side Swift, the next step is to get it hosted somewhere and running all the time. Personally, I use <a href="https://digitalocean.com/">DigitalOcean</a> for my hosting running an Ubuntu VPS. Most of the instructions here are fairly generic, but depending on the distribution of Linux (or Unix) you're running, you may need to switch some things up.</p><h2>Setting Up Swift</h2><p>The first thing you'll want to do after getting your VPS is getting Swift 5 (the latest version as of writing this post) setup and running on it.</p><p>As a pre-requisite you'll need clang installed.</p><pre data-language="bash" class="hljs"><code>sudo apt-get install clang
</code></pre><p>You'll then want to download the latest version from <a href="https://swift.org/download/">swift.org</a>.</p><p><strong>Note</strong>: As of this writing, packages are only pre-built for Ubuntu, so if you're using something else, you'll need to compile your own version.</p><p>You'll want to unpack the downloaded Swift package, and then add it to your <code>$PATH</code>:</p><pre data-language="bash" class="hljs"><code>tar xzf swift-&lt;VERSION&gt;-&lt;PLATFORM&gt;.tar.gz
<span class="hljs-built_in">echo</span> <span class="hljs-string">'export PATH=/path/to/swift-&lt;VERSION&gt;-&lt;PLATFORM&gt;/usr/bin:"${PATH}"'</span> &gt;&gt; ~/.bashrc
</code></pre><p>After that, you should be able to run Swift from the commandline.</p><pre data-language="bash" class="hljs"><code>&gt; swift
Welcome to Swift version 5.0 (swift-5.0-RELEASE).
Type :<span class="hljs-built_in">help</span> <span class="hljs-keyword">for</span> assistance.
  1&gt; var a = 1 + 1
a: Int = 2
</code></pre><h2>Not Running Swift as Root</h2><p>A <em>really bad thing™</em> to do would be to run your Swift server as root… if someone manages to hack your server, they'll be able to wreck havoc as root. You'll want to configure your server to run as an unprivileged user.</p><pre data-language="bash" class="hljs"><code>sudo adduser swiftserver
sudo usermod -aG sudo swiftserver
</code></pre><p>This'll create a new user called <code>swiftserver</code> that can run privileged commands with sudo if needed (ps: <strong>don't</strong> start your server with <code>sudo</code>).</p><p>You'll want to logout and then log back in as the <code>swiftserver</code> user.</p><h2>Serving Server-Side Swift</h2><p>To serve the server, you can actually just run it directly via <code>swift run</code> and it'll be served (by default) on port 8080. However, this doesn't support SSL or any of the nice things that come with web servers (security, disabling access to folders, etc.). Whilst I'm sure you could do all of this by hand, I wanted to focus mostly on serving blog content and not the intricacies of web servers. To serve the Swift app, I setup <a href="https://www.nginx.com">NGINX</a> and setup a reverse-proxy to my Swift app running. This way, the Swift app would run on a different port and NGINX would communicate with it (instead of it being the whole webserver).</p><p>It looks something like this:</p><p>[browser: https://blog.mysite.com/blog/entry] -&gt; [NGINX] -&gt; [swift-server] -&gt; [NGINX] -&gt; [browser]</p><p>Setting up NGINX is pretty easy:</p><pre data-language="bash" class="hljs"><code>sudo apt-get install nginx
systemctl status nginx

<span class="hljs-comment"># DigitalOcean needs to have the firewall configured via ufw</span>
<span class="hljs-comment"># This opens both port 80 and 443, but you may want to use just Nginx HTTPS to be more secure after you've setup HTTPS</span>
sudo ufw allow <span class="hljs-string">'Nginx Full'</span> 
</code></pre><p>Next you'll want to configure NGINX.</p><p>Create a file at <code>/etc/nginx/sites-available/swift-blog</code> (replace <code>swift-blog</code> with whatever your binary is called) and fill it out with something like this:</p><pre data-language="yaml" class="hljs"><code><span class="hljs-string">server</span> <span class="hljs-string">{</span>
  <span class="hljs-string">server_name</span> <span class="hljs-string">blog.mysite.com;</span>

  <span class="hljs-string">location</span> <span class="hljs-string">/</span> <span class="hljs-string">{</span>
    <span class="hljs-string">proxy_set_header</span>        <span class="hljs-string">Host</span> <span class="hljs-string">$host:$server_port;</span>
    <span class="hljs-string">proxy_set_header</span>        <span class="hljs-string">X-Real-IP</span> <span class="hljs-string">$remote_addr;</span>
    <span class="hljs-string">proxy_set_header</span>        <span class="hljs-string">X-Forwarded-For</span> <span class="hljs-string">$proxy_add_x_forwarded_for;</span>
    <span class="hljs-string">proxy_set_header</span>        <span class="hljs-string">X-Forwarded-Proto</span> <span class="hljs-string">$scheme;</span>

    <span class="hljs-string">proxy_pass</span>          <span class="hljs-string">http://127.0.0.1:8888;</span>
    <span class="hljs-string">proxy_read_timeout</span>  <span class="hljs-number">90</span><span class="hljs-string">;</span>

    <span class="hljs-string">proxy_redirect</span>      <span class="hljs-string">http://127.0.0.1:8888</span> <span class="hljs-string">http://mysite.com;</span>

    <span class="hljs-comment"># Required for new HTTP-based CLI</span>
    <span class="hljs-string">proxy_http_version</span> <span class="hljs-number">1.1</span><span class="hljs-string">;</span>
    <span class="hljs-string">proxy_request_buffering</span> <span class="hljs-string">off;</span>
  <span class="hljs-string">}</span>
<span class="hljs-string">}</span>
</code></pre><p>Lastly, you'll want to activate this configuration by symlinking it:</p><pre data-language="bash" class="hljs"><code>sudo ln -s /etc/nginx/sites-available/swift-blog /etc/nginx/sites-enabled/swift-blog

<span class="hljs-comment"># Reload NGINX</span>
sudo systemctl restart nginx
</code></pre><p>You'll want to set the <code>server_name</code> to use the subdomain of where you're hosting this server, and <code>proxy_pass</code> and <code>proxy_redirect</code> accordingly (this is where you supply the port your server will be running on). Now whenever you visit <code>blog.mysite.com</code> you'll be sending web requests to your Swift app via NGINX.</p><p>There's a lot of configuration options available here, and if you'd like to setup a separate webserver alongside this app, you can do so in this file as well. For more information on that check out DigitalOcean's tutorial <a href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04">here</a>.</p><h2>Securing the Server</h2><p>The next thing you'll want to do is serve your content securely using SSL. Whilst this is technically optional, I think it's much more future proof and safer to setup for people consuming your content. There's countless ways to set this up, but the easiest way I found was done by setting up <a href="https://cloudflare.com/">Cloudflare</a> (thanks <a href="https://twitter.com/_inside">@_inside</a>!). When you setup your domain and verify it through Cloudflare you'll be given a certificate and a private key. You'll want to put those on your server somewhere (I used <code>/etc/cloudflare/</code>). You'll also want to download the Origin Pull certificate <a href="https://support.cloudflare.com/hc/en-us/articles/204899617-Authenticated-Origin-Pulls#section6">here</a> and save that into the same directory as your Cloudflare certificates.</p><p>The last thing you'll need is to generate a <code>dhparam.pem</code> and save that into the same directory as well. You can do that via this command:</p><pre data-language="bash" class="hljs"><code>sudo openssl dhparam -out /etc/cloudflare/dhparam.pem 4096
</code></pre><p>After you've got all those files, you'll want to edit the top of the <code>server</code> area of your <code>swift-blog</code> config with the following:</p><pre data-language="yaml" class="hljs"><code><span class="hljs-string">server</span> <span class="hljs-string">{</span>
  <span class="hljs-string">listen</span> <span class="hljs-number">443</span> <span class="hljs-string">ssl</span> <span class="hljs-string">http2;</span>
  <span class="hljs-string">listen</span> <span class="hljs-string">[::]:443</span> <span class="hljs-string">ssl</span> <span class="hljs-string">http2;</span>
  <span class="hljs-string">ssl</span> <span class="hljs-string">on;</span>
  
  <span class="hljs-string">ssl_certificate</span>               <span class="hljs-string">/etc/cloudflare/cloudflare_origin_cert.pem;</span>
  <span class="hljs-string">ssl_certificate_key</span>           <span class="hljs-string">/etc/cloudflare/cloudflare_origin_privatekey.pem;</span>
  <span class="hljs-string">ssl_dhparam</span>                   <span class="hljs-string">/etc/cloudflare/dhparam.pem;</span>
  <span class="hljs-string">ssl_client_certificate</span>        <span class="hljs-string">/etc/cloudflare/origin-pull-ca.pem;</span>
  <span class="hljs-string">ssl_verify_client</span> <span class="hljs-string">on;</span>

  <span class="hljs-string">...</span>
</code></pre><p>This change will enable serving content with NGINX using HTTPS / SSL.</p><p>After making these changes you'll also want to change your firewall settings and reload NGINX.</p><pre data-language="bash" class="hljs"><code>sudo ufw allow <span class="hljs-string">'Nginx HTTPS'</span> 
sudo systemctl restart nginx
</code></pre><h2>Keeping Your Server Alive</h2><p>Sometimes apps crash or servers fail, so you need to ensure that your Swift app can restart itself in case it fails in any way; that way it can still communicate with NGINX and the web. Setting this up with Ubuntu is pretty easy, you just need to create and register a service for it.</p><p>Simply create a file at <code>/etc/systemd/system/swift-blog.service</code> with the following contents:</p><pre data-language="ini" class="hljs"><code><span class="hljs-section">
[Unit]</span>
<span class="hljs-attr">Description</span>=swift-blog
<span class="hljs-attr">After</span>=network.target
<span class="hljs-section">[Service]</span>
<span class="hljs-attr">Type</span>=simple
<span class="hljs-attr">Environment</span>=<span class="hljs-string">"PORT=8888"</span>
<span class="hljs-attr">WorkingDirectory</span>=/path/to/your/swift-blog-folder
<span class="hljs-attr">ExecStart</span>=/path/to/your/swift-blog-folder/swift-blog
<span class="hljs-attr">Restart</span>=always
<span class="hljs-attr">StandardOutput</span>=file:/var/log/swift-blog.log
<span class="hljs-section">[Install]</span>
<span class="hljs-attr">WantedBy</span>=multi-user.target
</code></pre><p>You'll then want to activate your server service using the following:</p><pre data-language="bash" class="hljs"><code>sudo systemctl start swift-blog
sudo systemctl <span class="hljs-built_in">enable</span> swift-blog
</code></pre><p>After that, you should be able to visit <a href="https://blog.mysite.com/">https://blog.mysite.com/</a> and your Swift server will be running!</p><h2>Conclusion</h2><p>Writing my whole blog in Swift and then getting it running as a fully fledged web app was a really neat endeavour. It was fun starting from square one and getting everything running from the ground up; I definitely learned a bunch and I hope in reading all of this you. It's still wild as a concept to me, being able to use all of my Cocoa knowledge I've built up over the years to use for a Linux server box. I'm still learning how to make it better, caching things, etc. so I'm always open to suggestions on how to improve.</p><p>Let me know how your own server-side Swift projects go and if you have any questions feel free <a href="https://www.twitter.com/b3ll">to ask</a>!</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20190417-Blogging-in-Swift</guid><title>Blogging in Swift</title><description></description><link>https://blog.adambell.ca/posts/20190417-Blogging-in-Swift</link><pubDate>Wed, 17 Apr 2019 00:00:00 -0400</pubDate><content:encoded><![CDATA[<h2>Introduction</h2><p>Recently I attended try! Swift in Tokyo, Japan (which was an absolutely fantastic conference), and there I heard about a lot of folks that were using (or beginning to use) Swift on the Server. Now that Swift has reached version 5, and its ABI is stable, I thought it'd be a great time to try it out for myself. I didn't really know what to write, but I saw that <a href="https://www.twitter.com/stroughtonsmith">@stroughtonsmith</a> had recently rewritten his blog as a static one being served by PHP and I thought that could be a pretty cool thing to make in Swift! My previous blog was hosted on Tumblr, and it ended up being a lot of maintenance to do simple things, which was pretty discouraging from wanting to write things. I wanted to write something that would make publishing a blog with media and code samples trivial without importing <a href="https://www.reddit.com/r/ProgrammerHumor/comments/6s0wov/heaviest_objects_in_the_universe/">thousands of dependencies</a>.</p><p>The end result however, well, you're reading it. As of this post, my entire personal website and blog runs on a server I wrote in Swift using <a href="[kituralink.com](https://www.kitura.io)">IBM's Kitura</a>, which, in-turn, is running on some Linux box <em>in the cloud</em>. I can easily write new posts, upload media and code samples, and the backing for it is all type-safe and native (thanks to Swift). Updating it is as easy as compiling an Xcode project, and there's no more need to trawl through arcane linux directories to find error logs.</p><p>This post will go over the basics of how I wrote my blog, and how you can get started writing your own. I wrote it in a way where you can get started with little server-side code experience, so hopefully this post gets you on your feet and helps you get started in the world of Server-Side Swift.</p><h3>🚨 Disclaimer 🚨</h3><p>In all honesty, my 15+ years of experience with server-side code has been:</p><ul><li>Publishing jQuery + HTML files with Transmit's upload button</li><li>Copying and pasting some PHP code off stackoverflow<ul><li>… and that's about it</li></ul></li></ul><p>So I went into this completely blind not knowing anything at all of what I'm supposed to be doing. ¯_(ツ)_/¯</p><p>I normally write apps, not distributed servers. This ended up being way outside my comfort zone, so I'm still learning, and if there's things I'm missing or could do better, please let me know!<br><strong>Pro-tip</strong>: Don't run your server as root. It's a <strong>very bad</strong> idea.</p><h2>SaaS, Swift as a Server</h2><p>Starting out, I didn't really know what I should be doing or how I should start. How does one get Swift working on Linux? How does the app I write in Swift produce HTML for browsers to read? In the past, if I wanted to write scripts for my website I'd just open a new PHP file and it'd work.</p><p>I started searching and was slammed with a wall of information:</p><ul><li>Use Kitura with Kubernetes and Bluemix!</li><li>Use a Vapor Docker image with Apache!</li><li>Use NGINX + SwiftNIO!</li><li>Setup Express and NodeJS… 🤔</li></ul><p>All of that was a lot of dense reading and background info on a lot of technolgies I've only heard in passing. Half the time I was thinking to myself <em>wtf is all of this?</em>. I decided to start with the basics and just see what I could get working so I ended up picking up Kitura because their support team were super nice and it seems as though they've been contributing a fair bit to Apple's open source projects too. I have nothing against any competing open source projects (i.e. Vapor), I just personally haven't used any of them.</p><p>Anyways, setting up Kitura is pretty simple:</p><pre data-language="bash" class="hljs"><code>brew install kitura

mkdir blog-test
<span class="hljs-built_in">cd</span> blog-test
kitura init
</code></pre><p><strong>Note</strong>: The name of the folder you run <code>kitura init</code> inside is the name of the target that will be created. Here we're using <code>blog-test</code>.</p><p>This'll give you a barebones project setup with the Swift Package Manager. I wanted to write things in Xcode, so I did the following:</p><p><code>swift package generate-xcodeproj</code></p><p>And that created an Xcode project I could build and run with.</p><p><strong>Note</strong>: This also adds a bunch of other stuff that I didn't end up using but could be helpful (i.e. Health, Analytics, etc.). They all are optional, so if you don't want them you can remove them.</p><p><code>⌘+R</code> and you'll get a web server running at <code>http://127.0.0.1:8080</code> or <code>http://localhost:8080</code></p><p><code>Application.swift</code> is the main entry point for things and here is where you'll setup routes. Routes are a way of parsing incoming network requests, doing some logic with them, and then giving back a response.</p><p>For example:</p><pre data-language="swift" class="hljs"><code>router.add(<span class="hljs-string">"/neat"</span>) { (response, something, something) <span class="hljs-keyword">in</span> 
  response.write(<span class="hljs-string">"neat! 📸"</span>)
}
</code></pre><p>Will output nothing but "neat! 📸" when you navigate to <code>http://localhost:8080/neat</code>. While that's cool and all, that doesn't really allow the dynamism of Swift to show, and it isn't that helpful for building sites easily. Swift + Stencils is something I adopted to make this far more easy.</p><h2>Stenciling HTML</h2><p>So Kitura provides out of the box support for <a href="https://github.com/stencilproject/Stencil">Stencil</a>. Stencil is a template language for Swift and is a way of adding preprocessor functionality to HTML. You can take a <strong>context</strong> defined in Swift and use that to <strong>generate</strong> or <strong>fill-in</strong> placeholders in the HTML. I needed to write a listing of all my blog entries, so I could write a stencil file like this:</p><pre data-language="html" class="hljs"><code><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {% for post in posts %}
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
        {{ post.title }}
      <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      {% endfor %}    
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre><p>And after using a JSON data structure like this:</p><pre data-language="json" class="hljs"><code>{
  <span class="hljs-attr">"posts"</span>: [
    {
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"My first blog post"</span>
    },
    {
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"My second blog post"</span>
    }
  ]
}
</code></pre><p>I could create something like this:</p><pre data-language="html" class="hljs"><code><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
       My first blog post
     <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
       My second blog post
     <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre><p>Neat huh? It's similar to writing inline PHP code for generating missing parts of HTML, or filling in fields as a page is being loaded. The difference, however, is Swift is supplying a single context object to the HTML stencil, which is what the stencil will be populated with.</p><h2>Serving Things in Swift</h2><p>To setup stenciling, we need to opt-in for it. You'll want to edit <code>Package.swift</code> to look something like this:</p><pre data-language="swift" class="hljs"><code><span class="hljs-comment">// swift-tools-version:5.0</span>
<span class="hljs-keyword">import</span> PackageDescription

<span class="hljs-keyword">let</span> package = <span class="hljs-type">Package</span>(
  name: <span class="hljs-string">"blog-test"</span>,
  dependencies: [
    .package(url: <span class="hljs-string">"https://github.com/IBM-Swift/Kitura.git"</span>, .upToNextMinor(from: <span class="hljs-string">"2.6.0"</span>)),
    .package(url: <span class="hljs-string">"https://github.com/IBM-Swift/HeliumLogger.git"</span>, from: <span class="hljs-string">"1.7.1"</span>),
    .package(url: <span class="hljs-string">"https://github.com/IBM-Swift/CloudEnvironment.git"</span>, from: <span class="hljs-string">"9.0.0"</span>),
    .package(url: <span class="hljs-string">"https://github.com/RuntimeTools/SwiftMetrics.git"</span>, from: <span class="hljs-string">"2.0.0"</span>),
    .package(url: <span class="hljs-string">"https://github.com/IBM-Swift/Health.git"</span>, from: <span class="hljs-string">"1.0.0"</span>),
    .package(url: <span class="hljs-string">"https://github.com/IBM-Swift/Kitura-StencilTemplateEngine.git"</span>, from: <span class="hljs-string">"1.8.0"</span>),
  ],
  targets: [
    .target(name: <span class="hljs-string">"blog-test"</span>, dependencies: [ .target(name: <span class="hljs-string">"Application"</span>), <span class="hljs-string">"Kitura"</span>, <span class="hljs-string">"HeliumLogger"</span>]),
    .target(name: <span class="hljs-string">"Application"</span>, dependencies: [ <span class="hljs-string">"Kitura"</span>, <span class="hljs-string">"CloudEnvironment"</span>, <span class="hljs-string">"SwiftMetrics"</span>, <span class="hljs-string">"Health"</span>, <span class="hljs-string">"KituraStencil"</span> ]),

    .testTarget(name: <span class="hljs-string">"ApplicationTests"</span> , dependencies: [.target(name: <span class="hljs-string">"Application"</span>), <span class="hljs-string">"Kitura"</span>, <span class="hljs-string">"HeliumLogger"</span> ])
  ]
)
</code></pre><p><strong>Note</strong>: At time of writing I'm using Swift 5 for this, so you may need to update <code>.swift-version</code> and ensure your Xcode version is at least 10.2. Also there's a strong chance these packages have updated versions now, so you'll also want to update those accordingly.</p><p>Then run the following to regenerate / update your project:</p><pre data-language="bash" class="hljs"><code>swift package update
swift package build-xcodeproj
</code></pre><p>Setting up stenciling templates isn't all that difficult. By default, Kitura will render template files provided in <code>Views/</code>. So let's create a folder named <code>Views</code> next to the <code>Sources</code> folder and inside <code>Views/</code> create a stencil file called <code>blog-posts.stencil</code>.</p><p>Fill it with something like this:</p><pre data-language="html" class="hljs"><code><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {% for post in posts %}
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
        {{ post.title }}
      <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      {% endfor %}    
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre><p>Next, we need to have our server render the specified template file when requested, so we need to setup a route for anytime someone visits <code>posts</code> to populate a data structure of all the posts for filling in the template.</p><p>In <code>Application.swift</code>, import <code>KituraStencil</code> add the following just before <code>Kitura.addHTTPServer(onPort: cloudEnv.port, with: router)</code>:</p><pre data-language="swift" class="hljs"><code><span class="hljs-comment">// Enable the stencil engine and add it to the router.</span>
router.add(templateEngine: <span class="hljs-type">StencilTemplateEngine</span>())

<span class="hljs-comment">// Create a data structure to be shown by the stencil.</span>
<span class="hljs-keyword">let</span> posts: [<span class="hljs-type">String</span>: <span class="hljs-type">Any</span>] = [
  <span class="hljs-string">"posts"</span>: [
    [
      <span class="hljs-string">"title"</span>: <span class="hljs-string">"My First Post"</span>
    ],
    [
      <span class="hljs-string">"title"</span>: <span class="hljs-string">"My Second Post"</span>
    ],
  ]
]

<span class="hljs-comment">// Anytime someone navigates to http://mysite.com/posts run this closure.</span>
router.<span class="hljs-keyword">get</span>(<span class="hljs-string">"/posts"</span>) { request, response, next <span class="hljs-keyword">in</span>
  <span class="hljs-keyword">do</span> {
    <span class="hljs-comment">// If it's successful in rendering, mark the response as OK.</span>
    <span class="hljs-keyword">try</span> response.render(<span class="hljs-string">"blog-posts.stencil"</span>, context: posts)
    response.status(.<span class="hljs-type">OK</span>)
  } <span class="hljs-keyword">catch</span> <span class="hljs-keyword">let</span> error {
    <span class="hljs-comment">// Otherwise, log out an error.</span>
    response.send(json: [<span class="hljs-string">"Error"</span>: error.localizedDescription])
  }

  <span class="hljs-comment">// Calling next will allow other parts of your server to respond to similar requests (rather than just halting here).</span>
  next()
}
</code></pre><p>Build and run, and if you did everything correctly, open Safari and navigate to <code>http://localhost:8080/posts</code>.</p><p>You should see something like this:</p><img src="https://blog.adambell.ca/assets/stencilposts.png" alt="image of rendered posts"/><p>Next steps here would be to write something to accept an arbitrary URL and use that to serve content dynamically. This would allow for linking back to specific posts via something like this:</p><p><code>http://localhost:8080/myPost</code></p><p>Kitura supports queries and variable parameters too, and it's pretty simple to declare:</p><pre data-language="swift" class="hljs"><code>router.<span class="hljs-keyword">get</span>(<span class="hljs-string">"/:postName"</span>) { request, response, next <span class="hljs-keyword">in</span>
  <span class="hljs-comment">// postName would be myPost in this case</span>
  <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> postName = request.parameters[<span class="hljs-string">"postName"</span>] <span class="hljs-keyword">else</span> {
    response.status(.notFound)
    <span class="hljs-keyword">return</span>
  }

  <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> do something with the post name.</span>

  next()
}
</code></pre><h2>Kitura Markdown</h2><p>One thing that you could do with that <code>postName</code> variable is use it to render a markdown file with a specific filename. Kitura supports it out of the box as well!</p><p>Add <code>KituraMarkdown</code> to your <code>Package.swift</code>:</p><pre data-language="swift" class="hljs"><code>.package(url: <span class="hljs-string">"https://github.com/IBM-Swift/Kitura-Markdown"</span>, from: <span class="hljs-string">"1.1.0"</span>),
</code></pre><p>And also add it as a dependency to the <code>Application</code> target:</p><pre data-language="swift" class="hljs"><code>.target(name: <span class="hljs-string">"Application"</span>, dependencies: [ <span class="hljs-string">"Kitura"</span>, <span class="hljs-string">"CloudEnvironment"</span>, <span class="hljs-string">"SwiftMetrics"</span>, <span class="hljs-string">"Health"</span>, <span class="hljs-string">"KituraStencil"</span>, <span class="hljs-string">"KituraMarkdown"</span> ]),
</code></pre><p>Then run and update things:</p><pre data-language="bash" class="hljs"><code>swift package update
swift package generate-xcodeproj
</code></pre><p>In <code>Application.swift</code> you'll want to import <code>KituraMarkdown</code> and add the rendering engine for it (just like the <code>StencilTemplateEngine</code>):</p><pre data-language="swift" class="hljs"><code><span class="hljs-keyword">let</span> markdownRenderer = <span class="hljs-type">KituraMarkdown</span>()
markdownRenderer.setRootPaths(rootPaths: [ <span class="hljs-string">"Views/blog"</span> ])
router.add(templateEngine: markdownRenderer)

<span class="hljs-keyword">let</span> blogFileServer = <span class="hljs-type">StaticFileServer</span>(path: <span class="hljs-string">"Views/blog"</span>)
router.<span class="hljs-keyword">get</span>(<span class="hljs-string">"/"</span>, middleware: blogFileServer)
</code></pre><p>Now anytime the server tries to render a markdown file inside <code>Views/blog</code> it'll convert the markdown file and render it as HTML. You'll also notice that we added a static file server. This is so that anytime a resource is referenced inside the markdown file (i.e. <code>![myimage](myimage.png)</code>), the server will know to transform that path <code>myimage.png</code> into something like <code>Views/blog/myimage.png</code>.</p><p>Create a markdown file called <code>markdown-test.md</code> inside <code>Views/blog/</code> and fill it with something like this:</p><pre data-language="markdown" class="hljs"><code>This is a markdown file!

<span class="hljs-section"># It Supports Big Headers</span>
<span class="hljs-section">## Smaller Ones</span>
<span class="hljs-section">### And Even Smaller Ones</span>

![<span class="hljs-string">cat</span>](<span class="hljs-link">meow.jpg</span>)
</code></pre><p><strong>Note</strong>: Don't forget about the image, feel free to swap it with whatever you like, but it's a good way to test. Just put it right next to the <code>markdown-test.md</code> file.</p><p>A lot of blog sites allow linking to specific blog articles usually in the form of <code>website.com/your-blog-entry-here</code> so we need to have a way of mapping everything after the <code>/</code> to a particular blog entry to render. To make things super simple, we can just map the filename. In this case, navigating to <code>http://localhost:8080/markdown-test</code> should render our markdown file.</p><p>To do this, we need to setup a route to handle that parameter. Kitura, again, makes this pretty easy to setup. Add the following after the <code>blogFileServer</code> setup code to allow the server to render arbitrarily specified markdown files:</p><pre data-language="swift" class="hljs"><code>router.<span class="hljs-keyword">get</span>(<span class="hljs-string">"/:postName"</span>) { request, response, next <span class="hljs-keyword">in</span>
  <span class="hljs-comment">// Gets the argument passed after the "/"</span>
  <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> postName = request.parameters[<span class="hljs-string">"postName"</span>] <span class="hljs-keyword">else</span> {
    response.status(.notFound)
    <span class="hljs-keyword">return</span>
  }

  <span class="hljs-comment">// Tries to render the markdown file named {postName}.md stored in the blog folder (contained in the Views folder)</span>
  <span class="hljs-keyword">try</span> response.render(<span class="hljs-string">"blog/\(postName).md"</span>, context: [<span class="hljs-type">String</span>: <span class="hljs-type">Any</span>]())
  response.status(.<span class="hljs-type">OK</span>)
  next()
}
</code></pre><p>Assuming everything worked, you'll have something that looks like this:</p><img src="https://blog.adambell.ca/assets/markdowntest.png" alt="markdown-rendered"/><h2>Serving / Securing Server-Side Swift</h2><p>This blog post is already gigantic, so I'll be writing more in Part 2 which will be coming soon! We'll be covering how to take all of this swift server code and putting it on a server. We'll also be talking about how to setup SSL so it's nice and secure for people to consume it.</p><h2>Closing Notes</h2><p>Learning all of this and building it over time was a lot of fun. It's inspired me to write a lot more, especially since a lot of the pains of blogging before have been fully removed in my own workflow, written by me. Any minute changes I want I can easily change, and it's built atop a pseudo-familiar platform to me. I hope you found this guide useful, and maybe it'll get you excited about writing Swift on the server too!</p><p>If you have any questions, feel free to give me a shout <a href="https://www.twitter.com/b3ll">on twitter</a>.</p><p>I can't wait to write more, definitely have some things planned to talk about (synths, sounds, etc.) but until then, I'm just praying that this server doesn't get taken down :P</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20150913-Making-Truly-Native-Native-Apps-on-Apple-Watch</guid><title>Making Truly Native Native Apps on Apple Watch</title><description></description><link>https://blog.adambell.ca/posts/20150913-Making-Truly-Native-Native-Apps-on-Apple-Watch</link><pubDate>Sun, 13 Sep 2015 01:09:00 -0400</pubDate><content:encoded><![CDATA[<p>Just wanted to add a bit of commentary to Steven’s <a href="https://www.highcaffeinecontent.com/blog/20150912-Native-UIKit-apps-on-Apple-Watch">awesome writeup</a> on the UIKit hax we did with Apple Watch… :D</p><blockquote><p>WatchKit apps are handcuffed, as it were, only able to display UI through the elements WatchKit provides. They cannot get the position of touches onscreen, or use swipe gestures, or multitouch.</p></blockquote><p>Seriously, it’s horrible. Being able to build proper apps would be so great, instead of simple ways to display JSON files with Interface Builder (yes, that’s basically what WatchKit currently is). Especially watch faces, I’d love to be able to build my own (even powered by Sprite Kit, I know the stock ones use it!), I’ve got so many ideas for things to build.</p><img src="https://blog.adambell.ca/assets/899d0bfc51744c6c56a4c23069578eec14b7f911bd4fbb1becafdc0f64c648d8.jpg"/><h2>Humanizing LLDB</h2><blockquote><p>I roped <a href="https://www.twitter.com/b3ll">@b3ll</a> into a torturous day &amp; night of testing things, he in a cafe across from WWDC (with <a href="https://www.twitter.com/saurik">@saurik</a> for much-needed moral support!), me across the Atlantic.</p></blockquote><p>10/10, can confirm, working as a remote, human, lldb / gdb session over iMessage was really weird. I’m pretty sure I have 30+ zipped up attempted builds, all of which had more and more aggressive naming schemes as time progressed :P (fku.zip). Sometimes the apps would install, sometimes they wouldn’t. Sometimes they’d insta-crash, sometimes they wouldn’t. Sometimes they’d just insta-crash Carousel.</p><p>¯_(ツ)_/¯</p><p>PS: Here’s a visual representation of how debugging went.</p><img src="https://blog.adambell.ca/assets/62503ca7b1b1ecbf60a213a7781ee3c10be7e1faabb85a64f9225db726321191.jpg"/><p><strong>:/</strong></p><img src="https://blog.adambell.ca/assets/f5149f10564b4b25395e65a8807dddc7827bac06ff46fc62bbadf8a80048c08e.jpg"/><p><strong>:(</strong></p><img src="https://blog.adambell.ca/assets/5955122ecbb93d6c5b0b02d6a27780a4e28c93d6efbce824574a093de4594b8d.jpg"/><p><strong>:D</strong></p><h2>Specs Pls</h2><p>After getting a basic UIKit app going, we started trying out various other iOS projects to see how they’d scale (scale… hehe… the watch is tiny… geddit?).</p><blockquote><p>PepperUICore classes are prefixed PUIC and are mostly subclasses of UIKit classes. Your root UIApplication subclass should be PUICApplication.</p></blockquote><p>While messing about with PepperCore, we whipped up an app to report the specs although whenever we tried to query the CPU speed it blew up. It’s got a really weird CPU(s?). Still… that’s a lot of RAM for a tiny watch!</p><img src="https://blog.adambell.ca/assets/58599bae56839756142cfa283054c0462fa5df8ce977aacd50d47f903bc3c84a.jpg"/><h2>Doomed Betas</h2><p>Next I tried porting Doom to the Apple Watch, since that’d be well, totally really super awesome. Doom is the most ported game of all time and it runs on <a href="http://tiwizard.com/downloads/doom/">calculators</a>, so surely it must work on the Apple Watch, right?</p><blockquote><p>watchOS can be so incredibly fickle when installing binaries. I’ve seen this with non-hacked regular WatchKit apps too, but you can get into a state where the OS refuses to install a binary and gives you random error messages. Sometimes rebooting fixes this, sometimes removing the app from your phone helps. Sometimes the exact same binary won’t install one minute, and works the next.</p></blockquote><p>I actually had it compiling and running at one point, but the fact that the builds were like 30mb made it excruciatingly painful to install and debug (transferring 30mb wirelessly took like 30 minutes). It also didn’t get very far, sadly. It was crashing on some weird and random OpenGL bugs, which I just blamed on the buggy 2.0 beta 1 software. What was even more “fun” was when I’d actually try and use the watch normally by raising my wrist, you know to check the time, and then seeing as it would just deadlock itself.</p><p>Yes… yes… I know… “Friends don’t let friends install iOS betas.” -<a href="https://twitter.com/mxweas/status/344229220488208384">@mxweas</a></p><img src="https://blog.adambell.ca/assets/ee361ba48808559369090ad8aef38cd29023aa7accd0b0f66f45136944a93fae.jpg"/><h2>Nano Canabalt</h2><p>What didn’t help was I had no debugging session to attach to, nor did I have any crashlogs (Steven says they take an hour… um no, more like a day ;P). To make things easier I migrated to a slightly smaller and more manageable codebase, Canabalt! Cramming everything to fit onscreen and make it playable took some messing about, but eventually it worked pretty great. Sound, controls, 60fps, the whole deal (the soundtrack is fantastic btw). Not quite sure how quickly it would drain the battery, but it seemed okay!</p><div class="iframe-wrapper">
  <iframe src="https://www.youtube.com/embed/9la8Soeh0ug" frameborder="0" allowfullscreen></iframe>
</div><h2>Closing Notes</h2><p>Working on this and keeping it somewhat secret was super fun, and a challenge at times, but now that it’s out in the open, make some cool stuff! If you do make anything cool, feel free to give me or @stroughtonsmith a shout! :D</p><img src="https://blog.adambell.ca/assets/68bbab28529427dd13b48192fbfda0fe42be2d4be71baf3b51d3202e6b6c65e1.png"/><blockquote><p>watchOS is iOS; most of the frameworks you expect to be there are actually on-disk. However, the SDK will not include them, or have complete headers for them.</p></blockquote><p>It’s so true. Everything “just works”, well, within reason. Once you’ve got ramped up and things working, do give it a shot at some point!</p><p>I know my <a href="https://itunes.apple.com/ca/app/click-wheel-keyboard/id993111285?mt=8">Click Wheel Keyboard</a> is just begging for an Apple Watch port… Digital Click Wheel Crown anyone? :D</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20140506-Making-Passbook-an-Address-Book</guid><title>Making Passbook an Address Book</title><description></description><link>https://blog.adambell.ca/posts/20140506-Making-Passbook-an-Address-Book</link><pubDate>Tue, 6 May 2014 06:12:00 -0400</pubDate><content:encoded><![CDATA[<h2>Intro</h2><p>Ever since Apple first announced Passbook two years ago, I've always liked the idea of using it to store business cards.</p><p>However, it'd be far more useful if it could store Pokemon cards... someone should file a radar on that...</p><p>Every year at WWDC (and any conference really) it's super fun to play the "trading card game" and collect various business cards from people. Some are really cool, some are so fantastic that the people that gave you their card ... will ask for it back -_-</p><p>The first day Passbook was announced was when I made my first card and hopefully this'll stir up some creative Passbook business cards come WWDC 2014!</p><p><strong>tl;dr</strong>: they're cool, you should make one.</p><h2>How do I Passbook?</h2><p>Making a Passbook business card is, well, easier than writing HTML! For the most part you're just filling in blanks in a JSON file. You create a folder, and inside that folder you put the main JSON file, throw in a few images, and BAM Passbook card (<em>waves hands</em>)!</p><p>Sharing them is just as easy, especially with iOS 7. With iOS 7 came AirDrop (a somewhat crippled version, fwiw) and with that you can share Passbook cards over AirDrop, or anywhere else from the standard iOS share sheet.</p><h2>How do I JSON?</h2><p>Let's look at mine as an example:</p><pre data-language="json" class="hljs"><code>{
  <span class="hljs-attr">"formatVersion"</span> : <span class="hljs-number">1</span>,
  <span class="hljs-attr">"passTypeIdentifier"</span> : <span class="hljs-string">"pass.adambell.businesscard"</span>,
  <span class="hljs-attr">"organizationName"</span> : <span class="hljs-string">"diffractive"</span>,
  <span class="hljs-attr">"serialNumber"</span> : <span class="hljs-string">"0x1337"</span>,
  <span class="hljs-attr">"teamIdentifier"</span> : <span class="hljs-string">"sekrit"</span>,
  <span class="hljs-attr">"description"</span> : <span class="hljs-string">"Adam Bell"</span>,
  <span class="hljs-attr">"generic"</span> : {
    <span class="hljs-attr">"primaryFields"</span> : [
      {
        <span class="hljs-attr">"key"</span> : <span class="hljs-string">"name"</span>,
        <span class="hljs-attr">"label"</span> : <span class="hljs-string">""</span>,
        <span class="hljs-attr">"value"</span> : <span class="hljs-string">"Mobile Developer"</span>
      }
    ],
    <span class="hljs-attr">"secondaryFields"</span> : [
      {
        <span class="hljs-attr">"key"</span> : <span class="hljs-string">"website"</span>,
        <span class="hljs-attr">"label"</span> : <span class="hljs-string">"Web"</span>,
        <span class="hljs-attr">"value"</span> : <span class="hljs-string">"www.adambell.ca"</span>,
        <span class="hljs-attr">"textAlignment"</span> : <span class="hljs-string">"PKTextAlignmentLeft"</span>
      },
      {
        <span class="hljs-attr">"key"</span> : <span class="hljs-string">"twitter"</span>,
        <span class="hljs-attr">"label"</span> : <span class="hljs-string">"Twitter"</span>,
        <span class="hljs-attr">"value"</span> : <span class="hljs-string">"@b3ll"</span>
      }
    ],
    <span class="hljs-attr">"auxiliaryFields"</span> : [
      {
        <span class="hljs-attr">"key"</span> : <span class="hljs-string">"email"</span>,
        <span class="hljs-attr">"label"</span> : <span class="hljs-string">"Mail"</span>,
        <span class="hljs-attr">"value"</span> : <span class="hljs-string">"someemail@gmail.com"</span>
      }
    ]
  },
  <span class="hljs-attr">"barcode"</span> : {
    <span class="hljs-attr">"format"</span> : <span class="hljs-string">"PKBarcodeFormatPDF417"</span>,
    <span class="hljs-attr">"message"</span> : <span class="hljs-string">"https URL here"</span>,
    <span class="hljs-attr">"messageEncoding"</span> : <span class="hljs-string">"iso-8859-1"</span>
  },
  <span class="hljs-attr">"backgroundColor"</span> : <span class="hljs-string">"rgb(221, 18, 29)"</span>,
  <span class="hljs-attr">"foregroundColor"</span> : <span class="hljs-string">"rgb(255, 255, 255)"</span>,
  <span class="hljs-attr">"labelColor"</span> : <span class="hljs-string">"rgb(255, 255, 255)"</span>,
  <span class="hljs-attr">"logoText"</span> : <span class="hljs-string">"Adam Bell"</span>,
  <span class="hljs-attr">"suppressStripShine"</span> : <span class="hljs-literal">true</span>
}
</code></pre><p>The meat of the pass is under the generic section. Depending on the type of pass you're making, you can specify a multitude of fields (like departure / arrival if you were making a flight ticket), but for our sake we're just re-purposing a generic pass. Your <code>teamIdentifier</code> is used to specify your signing identity if you want to sign your pass but we'll get to that.</p><img src="https://blog.adambell.ca/assets/71e5752bad99360f607728183a8786bd4f78c6ba1bb0afa1fac22f9dbc45719c.png" alt="PassbookPreview"/><p>Here's how I tailored my pass as a business card:</p><h3>Description</h3><p>I don't really know if this used on iOS, but on Windows Phone it shows up in the live tile... more on this later.</p><h3>Primary Fields</h3><p>Set the value of <code>name</code> to a title for yourself, I kept <em>Mobile Developer</em> to keep things nice and simple. If you want to be fancy, might I recommend something like <em>"iOS Connoisseur"</em> (complete with air quotes)?</p><ul><li><strong>Side-Note</strong>: Each of these fields also has a label which is basically just a way to define what it is. The key can be whatever you want, as long as it's unique ('name' could be 'title', or even 'panda' if you really want to be 'cool').</li></ul><h3>Secondary Fields</h3><p>Here you get up to two fields to specify information (after that it looks kinda stupid with text all smushed together). I chose my twitter handle and website, since they're the easiest way to show off what I've done as well as get quickly in contact.</p><h3>Auxiliary Fields</h3><p>You get 1-2 more fields for info. I chose my email, since I'd rather people use it as a last resort (for most things) ;)</p><h3>Barcode</h3><p>This is the fun part. With iOS 7 came the ability to scan barcodes to download Passbook passes. It uses the same wicked fast iTunes gift card scanning / redeeming tech, but comes with some minor annoyances.</p><p>First off, the link specified here <strong>must</strong> be HTTPS. <em>...unless of course you break PKAllowHTTP() ;)</em></p><p>You get 3 types to pick from:<br>- Aztec<br>- QR<br>- Standard barcode (which I think looks best)<br><br>If you choose Aztec or QR, the rest of the card just ends up being a massive zebra.</p><p>Also, you might want to enable <code>suppressStripShine</code>, last thing you want is your pass looking like a shiny zebra (unless you like <a href="http://bulbapedia.bulbagarden.net/wiki/Blitzle_(Pok%C3%A9mon)">shiny pokémon</a>!)</p><h3>Everything Else</h3><ul><li>backgroundColor: well... the background colour (in rgb format)</li><li>foregroundColor: you guessed it! the foreground colour (in rgb format)</li><li>logoText: the text that shows at the top of the Pass</li><li>If you drop a logo.png (don't forget @2x assets), Passbook will display your logo in the top left.</li><li>If you drop a thumbnail.png (don't forget the @2x assets), Passbook will display a photo in the middle of the pass.</li><li>On the back side you can provide additional info, but I didn't feel it was necessary (personally).</li></ul><h3>"Security" Notes</h3><ul><li><strong>Update</strong>: I was nice and decided to upload a direct link to a version of Apple's signpass utility which skips any .DS_Store files from being added to the pkpass file <a href="http://www.adambell.ca/blog/signpass.zip">here</a>.</li></ul><p>You can invoke it like so:</p><pre data-language="bash" class="hljs"><code>pkpass -p &lt;some folder&gt; -o &lt;outputfile.pkpass&gt;
</code></pre><ul><li>You <strong>need</strong> to sign your pass. Apple has some great notes and a sample signing utility <a href="https://developer.apple.com/library/ios/documentation/userexperience/conceptual/PassKit_PG/Chapters/YourFirst.html">here</a>. So get ready for some provisioning profile dancing!</li><li>Read that ^</li><li>If you want to share your pass via barcode:<ul><li>It needs to be hosted on an HTTPS address</li><li>It needs to be distributed with <code>pkpass</code> as the file extension.</li><li>It needs to be distributed with <code>application/vnd.apple.pkpass</code> specified as the MIME type.</li></ul></li><li>Amazon S3 provides all this!</li><li>Read the first point again.</li></ul><h2>Enter the Windows Phone</h2><p>What's even more awesome is Microsoft decided to be nice (or lazy :D) and support Apple Passbook cards in Windows Phone 8.1! They work out of the box too! You can simply email a pass to your Windows Phone and add it that way.</p><p>What's nice is you literally have to change nothing, it just works.</p><p>That's a first for Microsoft. :P</p><img src="https://blog.adambell.ca/assets/a6d5a5de3fdd5057a31d0f87d8be426e70eb9606a438c17b67bd29edcca19148.png" alt="WindowsPhonePreview"/><img src="https://blog.adambell.ca/assets/0bcafae13db436abbb5d70589cf1754f95413780450529ca3bad29aea728c92f.png" alt="WindowsPhonePreview2"/><p>As I mentioned earlier, <code>description</code> is the field that defines what will show on the Windows Phone Start Screen when you add your pass as a live tile (super quick access to contact details!). Best practice for this is to keep it short and simple unless you have an arbitrarily long name that just overflows everything...</p><ul><li><strong>Side-Note</strong>: One thing I did notice about loading passes with Windows Phone, if it throws an extremely useful error 0, your JSON is probably malformed. Run it through jsonlint or something equivalent, fix it, and then you should be good to go! :D</li></ul><h2>Party Time</h2><p>If you haven't used Passbook yet, this might be a fun way to start. Might put you on the "bleeding edge" of business cards! :D</p><p><strong>PS</strong>: Pokémon Passbook cards really should be a thing.<br><br><img src="https://blog.adambell.ca/assets/3ffdf3986b15bae084281102ec6f5a61cfb64a4ecf6e600e7a46c683ca218040.png" alt="Mewtwo Card"/><br><br>I wish I could have a larger strip image, a gold border, and a purple background, but the current Passbook spec doesn't allow it. :(</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20140124-Here-Fishy-Fishy</guid><title>Here Fishy, Fishy...</title><description></description><link>https://blog.adambell.ca/posts/20140124-Here-Fishy-Fishy</link><pubDate>Fri, 24 Jan 2014 06:14:00 -0500</pubDate><content:encoded><![CDATA[<h2>Intro</h2><p>I'm not a huge vim person... yet. I like IDEs, usually... (I'm looking at you Visual Studio). Therefore I'll only really use a shell for <a href="http://www.cycript.org">cycript</a> or other random ssh sessions and hax and such.<br>However, <a href="http://fishshell.com">fish</a> is making the shell fun.</p><h2>What the fish?</h2><p>So what is <a href="http://fishshell.com">fish</a> anyways? While it sounds like the result of preparations of a sushi plate, it's this really awesome shell replacement. Bash, zsh, tcsh (ew), they're all shells that we can use with a terminal to control the operating system or run a bunch of programs without the need for a mouse.</p><p><strong>tl;dr</strong>: They're what Hollywood uses to make someone look like a "<a href="http://www.hackertyper.com">hacker</a>".</p><p>Anyways, fish does all that and more. You get <strong>ALL the colours</strong> with term256 support (it looks nice). You also get auto-completion, which is awesome.</p><p>Did I mention it likes emoji? Yeah! Sheep Shell! (or <a href="https://twitter.com/stroughtonsmith/status/413431843460227072">baaaaaaash</a> if you're <a href="https://www.twitter.com/stroughtonsmith">@stroughtonsmith</a>)!<br><img src="https://blog.adambell.ca/assets/5abf0121fe40b17bda2579c86b566ce7fe7ab902d29a458f5c7ad4279aac2f27.png" alt="sheepshell"/><br><br><br>## git... add? commit? push? --force push? Fish shell does this crazy magical thing, that parses man documents to give you possible auto-completions for whatever you're typing in.<br><br>ls -? yep.<br>ps -? yep.<br>ssh -? yep.<br><br>Look (git):<br><img src="https://blog.adambell.ca/assets/2a2cea3575297192314754f007512740e2d7f2b3cf1e9f5f472f1e4bbfc8663d.png" alt="git-autocomplete"/><br><br>Simply type in a command and hit tab (as you normally would in most shells to auto-complete directories and such). It also auto-suggests previous commands that you've used in the past so:</p><pre data-language="bash" class="hljs"><code><span class="hljs-built_in">history</span> | grep git
// OH RIGHT I REMEMBER
git --force push
</code></pre><p>becomes:</p><pre data-language="bash" class="hljs"><code>git --force push &lt;CTRL+F&gt;
</code></pre><p>It's super simple, and looks great too. To accept a completion, simply hit CTRL+F (which I assume you can change if you really want to, I haven't bothered).</p><p>You can add to this as well, such as <a href="https://github.com/bpinto/oh-my-fish">bpinto's oh my fish</a> (which I highly recommend).</p><p>In addition, it auto-completes directories and it tells you if a directory path is valid or not (with colours!): <img src="https://blog.adambell.ca/assets/ee523194d9a48e27de65daa0cae4c779da64913300b30837ea9990f837629f10.png" alt="cd-valid"/><br><img src="https://blog.adambell.ca/assets/09849bbfb6a2b0a8243a9cba88e9249e98ae67a41a0bba130b0a72accb4ef14e.png" alt="cd-invalid"/><br><br>## script.fish Scripting in fish is actually quite easy. It doesn't like a lot of bash's syntax, but it's super simple to pick-up. Here's a quick primer:</p><pre data-language="bash" class="hljs"><code><span class="hljs-meta">#!/bin/bash
</span>
<span class="hljs-built_in">export</span> hey=<span class="hljs-string">"sup yo"</span>
<span class="hljs-built_in">alias</span> ls=<span class="hljs-string">"say l s"</span>
<span class="hljs-function"><span class="hljs-title">whereami</span></span> () { 
  <span class="hljs-built_in">echo</span> `<span class="hljs-built_in">pwd</span>`
}
</code></pre><pre data-language="sh" class="hljs"><code><span class="hljs-meta">#!/usr/local/bin/fish
</span>
<span class="hljs-built_in">set</span> -x hey <span class="hljs-string">"sup yo"</span>
<span class="hljs-built_in">alias</span> ls <span class="hljs-string">"say l s"</span>
<span class="hljs-keyword">function</span> whereami()
  <span class="hljs-built_in">echo</span> (<span class="hljs-built_in">pwd</span>)
end
</code></pre><p>Basically replace <code> </code> with ( ) and remove some square brackets. It's well <a href="http://fishshell.com/docs/current/index.html">documented</a> too, so be sure to check that out. Also, if you still want to use scripts from other shells, just use a hashbang (#!/bin/sh) and it'll work as expected. You can write scripts and save them as functions to call at your leisure, just write the script and stick it in:</p><pre data-language="undefined" class="hljs"><code>
~/.config/fish/functions/
</code></pre><p>Also, functions are super quick to write and save in the shell:</p><pre data-language="undefined" class="hljs"><code>
00:21 adam > function whereami
               echo (pwd)
             end
00:21 adam > funcsave whereami
00:21 adam > whereami
/Users/Adam
</code></pre><p>In addition, you can find your equivalent of a .bashrc / .bash_profile in:</p><pre data-language="sh" class="hljs"><code>~/.config/fish/config.fish
</code></pre><p>From there you can edit your greeting and prompt or add other environment variables:</p><pre data-language="sh" class="hljs"><code><span class="hljs-meta">#!/usr/local/bin/fish
</span>
<span class="hljs-keyword">function</span> fish_greeting
  <span class="hljs-built_in">echo</span> The time is currently (date).
end

<span class="hljs-built_in">set</span> -x PATH /usr/<span class="hljs-built_in">local</span>/bin <span class="hljs-variable">$PATH</span>

<span class="hljs-keyword">function</span> fish_prompt
  <span class="hljs-built_in">printf</span> <span class="hljs-string">"%s\n%s &gt;"</span> (<span class="hljs-built_in">pwd</span>) (whoami)
end
</code></pre><h2>sushi</h2><p>Fish is great, and it's fun to change things up!<br><br>Do I recommend it? Sure!<br>Do I not recommend it? Sure!<br><br>Only way to know if you'll like it is to try it (if you do launch it from another shell, sometimes it screws up text input). Speaking of trying things, I've also done this (bye nano :( ):</p><pre data-language="sh" class="hljs"><code><span class="hljs-keyword">function</span> nano
  vim <span class="hljs-variable">$argv</span>
end
</code></pre>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20140114-Dynamic-iOS-Multitasking</guid><title>Dynamic iOS Multitasking</title><description></description><link>https://blog.adambell.ca/posts/20140114-Dynamic-iOS-Multitasking</link><pubDate>Tue, 14 Jan 2014 21:42:00 -0500</pubDate><content:encoded><![CDATA[<h2>Intro</h2><p>iOS 4 brought us the wonderful feature to switch between apps quickly, and iOS 7 made this even more interactive through use of live previews of apps.</p><p>I noticed an <a href="http://vpdn.github.io/articles/iOS7-card-view/">article written by @vpdn</a> shared on <a href="https://twitter.com/marcedwards/status/422287961778970624">twitter</a> about making this switcher a little more lively through use of curated app content for multitasking. In other words, re-purposing the iOS 7 switcher as a sort of dashboard / widget interface for your applications.</p><p>I wanted to try and further extend this.</p><h2>ALL the Apps</h2><p>The iOS 7 switcher is, as I see it, Exposé (for the Mac) brought to iOS. It gives you an overview of everything that's running (and that has been running) sorted in order of usage. This is displayed through previews of applications, as well as their respective icons and titles. However, it stops there, and doesn't really provide any insight to anything else.</p><h2>Extensions</h2><p>A neat example of extending this functionality is re-purposing them as widgets, for example, Facebook or Instagram. Imagine a user switching from the twitter app and noticing a widget like Facebook displaying some photos they were just tagged in. Another usage could be to show coverart for the currently playing as another form of heads up display. These give the switcher a more personalized and unique experience (than simply images which are basically just the app's Default.png).</p><h2>The Fun Part</h2><p>In order to conserve battery life, and free up CPU time, iOS throttles down applications that have been dismissed; videos stop playing, NSTimers get paused, applications don't get any updates. When the app enters background state a current snapshot of the application's window is performed and saved to disk to be shown as the preview:</p><pre data-language="objectivec" class="hljs"><code><span class="hljs-comment">// Depending on orientation it'll append -Portrait, -LandscapeLeft, etc. to the image saved </span>
[[<span class="hljs-built_in">UIApplication</span> sharedApplication] _saveSnapshotWithName:<span class="hljs-string">@"UIApplicationAutomaticSnapshotDefault"</span>];
</code></pre><p>This is just a static image, and the rendering context for your application is paused when the application enters background state. So, currently, there's no way to alter that without breaking your app (or making Apple's App Review very <strong>angry face</strong> with you), or so I thought...</p><p>See with iOS 7 they introduced some awesome backgrounding features, one of which being Background App Refresh! This allows developers to update their applications in the background (like Facebook, Twitter, etc.) to save users a few "pull to refreshes". When the user returns to an app that's been updated in the background, it'll always feature the latest content.</p><p>When a backgrounded app is refreshed, the OS does something like this:</p><ol><li>Notification for background fetch comes in for application</li><li>Wake application using <code>-[UIApplication _shouldFakeForegroundTransitionForBackgroundFetch]</code></li><li>Application handles network request for update</li><li>Application refreshes UI to match said request</li><li>Snapshot the whole window! (<code>-[UIApplication _saveSnapshotWithName:]</code> shown above)</li><li>Send application back to background</li><li>Show snapshot in Multitasking.</li></ol><p>During this it eventually calls (with proper parameters obviously):</p><pre data-language="objectivec" class="hljs"><code>[[<span class="hljs-built_in">UIApplication</span> sharedApplication] _replyToBackgroundFetchRequestWithResult:<span class="hljs-number">0</span>
                                                    remoteNotificationToken:<span class="hljs-string">@"token"</span>
                                                             sequenceNumber:@(someNumber)
                                                  updateApplicationSnapshot:(<span class="hljs-literal">YES</span> || <span class="hljs-literal">NO</span>)]; <span class="hljs-comment">// ohai</span>
</code></pre><p>So here's the fun part, this can be horribly abused :D!</p><p>Let's re-purpose the app switcher preview!</p><p>Whenever we refresh the app in the background, why not just throw a new UIView on top of everything to display ...and hook everything up to a CADisplayLink? <strong>&gt;:D</strong></p><pre data-language="objectivec" class="hljs"><code><span class="hljs-comment">/* UIApplicationDelegateSubclass.m */</span>
- (<span class="hljs-keyword">void</span>)applicationDidEnterBackground:(<span class="hljs-built_in">UIApplication</span> *)application 
{
  _backgroundID = [application beginBackgroundTaskWithExpirationHandler:^{}];
}

- (<span class="hljs-keyword">void</span>)applicationDidBecomeActive:(<span class="hljs-built_in">UIApplication</span> *)application 
{
  [application endBackgroundTask:_backgroundID];
}


<span class="hljs-comment">/* UIViewControllerSubclass.m */</span>
- (<span class="hljs-keyword">void</span>)viewDidLoad 
{
  [<span class="hljs-keyword">super</span> viewDidLoad];
  [<span class="hljs-built_in">CADisplayLink</span> displayLinkWithTarget:<span class="hljs-keyword">self</span> selector:<span class="hljs-keyword">@selector</span>(updateALLTheThings)];
}

- (<span class="hljs-keyword">void</span>)updateALLTheThings 
{
  [[<span class="hljs-built_in">UIApplication</span> sharedApplication] _replyToBackgroundFetchRequestWithResult:<span class="hljs-number">0</span>
                                              remoteNotificationToken:<span class="hljs-string">@"no u"</span>
                                                       sequenceNumber:@(<span class="hljs-number">1337</span>)
                                            updateApplicationSnapshot:<span class="hljs-literal">YES</span>];
}
</code></pre><div class="iframe-wrapper">
  <iframe src="https://blog.adambell.ca//www.youtube.com/embed/ub3OuEREu2c%3Frel=0" frameborder="0" allowfullscreen></iframe>
</div><p>Tada! Dynamic application previews in Multitasking!</p><ol><li>Don't /ever/ do this. :P</li><li>If you try this on backgrounded GL applications, it'll explode and crash.</li><li>This is not App Store-safe and will be an insta-deny.</li></ol><h2>The Sane Approach (aka App Store-safe-ish)</h2><p>Since all of this is governed by the background app refreshes, and your UI will automatically update anyways... why not put that to good use?</p><p>Take Instagram for example, you're always going to see a timeline of photos in the app, and seeing a tableview as an application preview doesn't really make sense. A more appropriate preview could be a photo slideshow for your timeline (kinda like Facebook Home). To prove my point, I made a demo of it <a href="https://github.com/b3ll/dynamiciospreviews">here</a>.</p><div class="iframe-wrapper">
  <iframe src="https://blog.adambell.ca//www.youtube.com/embed/k8tU9lVyt80%3Frel=0" frameborder="0" allowfullscreen></iframe>
</div><p>Basically when my demo goes into the background, a background task is created for an indefinite amount of time (10mins most likely, until watchdog or another application kills it), and when it resumes said task is cancelled. By doing this I can keep the application running (swapping photos in the slideshow) and just apply them as an overlay.</p><p><strong>However</strong>, one could do this without using private API (and no, it's not witchcraft):</p><pre data-language="objectivec" class="hljs"><code>- (<span class="hljs-keyword">void</span>)application:(<span class="hljs-built_in">UIApplication</span> *)application performFetchWithCompletionHandler:(<span class="hljs-keyword">void</span> (^)(<span class="hljs-built_in">UIBackgroundFetchResult</span>))completionHandler 
{
  <span class="hljs-comment">// Update my preview and do cool stuff here</span>
  <span class="hljs-comment">// Maybe add a UIImageView on top of everything?</span>
  completionHandler(<span class="hljs-built_in">UIBackgroundFetchResultNewData</span>);
}
</code></pre><p>Obviously you'll need to setup iOS 7 backgrounding by altering your Info.plist and such (you'll find more of that in the iOS 7 documentation).</p><p>In addition, you could always try providing a different overlay to summarize information last displayed in your application through use of:<br><code></code>`objectivec</p><ul><li>(void)applicationWillResignActive:(UIApplication *)application <code></code>`</li></ul><p>Give it a go! Might be neat to see a more personal iOS 7 App Switcher :)</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20140114-Breaking-Chat-Heads-Out-of-the-iOS-Sandbox</guid><title>Breaking Chat Heads out of the iOS Sandbox</title><description></description><link>https://blog.adambell.ca/posts/20140114-Breaking-Chat-Heads-Out-of-the-iOS-Sandbox</link><pubDate>Tue, 14 Jan 2014 21:28:00 -0500</pubDate><content:encoded><![CDATA[<h2>Background Info</h2><p>On April 12th, 2013, Facebook released Facebook Home, a completely new mobile experience available solely to Android users. With Home came Chat Heads, a wickedly cool way to chat with your friends, in a way that makes that “face-to-face conversation experience” a little more feasible with text messaging. The minute I saw it, I thought “I can make this!”.</p><p>Using box2d as a boilerplate, I started working with giving contact photos the same (or similar anyways) physics that powers Chat Heads. I got some progress, and made it system-wide, but it wasn’t even close to being complete. It wasn’t but 2-3 days later that Chat Heads was announced for iOS. However, due to Apple’s sandboxing and policies, it was solely contained in the Facebook app :(</p><img src="https://blog.adambell.ca/assets/635e670bc21e476fbf91eb52c817ccb7f9036f1f35327598dfa77b6aa4e6b282.png" alt="box2d"/><p>STOP. APP STORE. INSTALL... was my first thought.</p><p>STOP. HOLD THE PHONE. HAX... was my second.</p><p>Why not “break” Chat Heads out of the iOS Facebook app?</p><h2>XPC and Watchdog</h2><p>The Facebook app is pretty complex, loads of view controllers and modules to make it all work together, but thankfully Chat Heads has its own view controller, and with that a view! Well that’s fantastic and all, you can’t just start ripping views out of an app and shoving it somewhere else, or so I thought...</p><p>I thought of using XPC to fix this. XPC is a framework developed by Apple that allows you to exchange things between running processes or applications. Those things are somewhat limited:</p><ol><li>XPC only plays nice with serializable objects (aka Dictionaries, Strings, and stuff)</li><li>Apple’s doing cooler things with views!</li></ol><p>When you open the multitasking bar, by double clicking the home button (or using that awesome slide-up gesture provided by Zephyr) Apple needed a way to move the current app upwards, or transform how it looks, without changing how the actual application renders. They didn’t want to mess with any custom code in the application, so they created another context to share the application’s rendering view (if that makes sense). SBAppContextHostManager handles all this. An application on iOS runs inside a UIWindow, a window that holds a bunch of views. So if we copy all the views inside that UIWindow, and render them inside another view, you can do whatever you want to this new view, without altering the original. Think of it as taking a photo, duplicating it, and messing with the duplicate. You can mess with it all you want, but the original stays the same. When you open the multitasking bar, Apple uses SBAppContextHostManager to create a new view and move it upwards to show the multitasking bar underneath, that way the original application’s layout isn’t touched.</p><p>I could do that with the Facebook app; render the Facebook app inside another view, and put it somewhere where it’s on top of everything else. This worked perfectly until you actually closed the Facebook app.</p><p>To save power, when an application is closed, the views aren’t rendered anymore (so the GPU can rest), unless you tell it explicitly not to! That's where some private API comes into play!</p><pre data-language="objectivec" class="hljs"><code>+[<span class="hljs-built_in">UIWindow</span> setAllWindowsKeepContextInBackground] 
</code></pre><p>... until a few minutes later when iOS decides to kill the Facebook app. :-|</p><p>This was the original problem shown in the <a href="http://www.theverge.com/2013/4/17/4235816/chat-heads-for-iphone-jailbreak-tweak">Verge article</a>; it freezes. On iOS there’s a daemon called watchdog. This daemon watches over everything running on iOS, and if you’re taking up too much memory or are in the background for too long, it’ll kill your app. It’s fantastic to save power and keep things running quickly, but annoying in this instance.</p><p>Some applications, however, can be granted permission to continue to run in the background, for example Reprise. Reprise is a music player, and if you give it backgrounding permissions, it’ll continue to play music after you close the app. Unfortunately Facebook isn’t a music player, and doesn’t have any special backgrounding permissions (other than for VOIP purposes), so I had to tweak things on a lower level than just the Facebook app.<br><br>## BackBoardServices</p><p>On iOS the main homescreen / lockscreen is called SpringBoard, but in iOS 6, Apple made things more interesting and decided to split up some of SpringBoard into backboardd. The result? SpringBoard handles more springing, and backboardd handles more of the behind-the-scenes application life managing. There’s a neat class in BackBoardServices (a private framework) called BKSProcessAssertion. This class allows you to give a certain application permissions to stay alive and not be killed by watchdog. So then I basically gave the Facebook app infinite backgrounding using the appropriate flags. To do this, I granted SpringBoard the ability to hand out BKSProcessAssertions to running applications (makes things easier tweak-wise). Yay! No more pausing, no more getting killed, and it’s <em>system-wide</em>!</p><pre data-language="objectivec" class="hljs"><code><span class="hljs-comment">// Replace this function using MobileSubstrate with a dylib into backboardd (or install MessageBox)</span>
<span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> hax_XPConnectionHasEntitlement(<span class="hljs-keyword">id</span> connection, <span class="hljs-built_in">NSString</span> *entitlement)
{
  <span class="hljs-comment">//Only grant the required entitlement</span>
  <span class="hljs-keyword">if</span> (xpc_connection_get_pid(connection) == PIDForProcessNamed(<span class="hljs-string">@"SpringBoard"</span>) &amp;&amp; [entitlement isEqualToString:<span class="hljs-string">@"com.apple.multitasking.unlimitedassertions"</span>])
  <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;

  <span class="hljs-keyword">return</span> orig_XPConnectionHasEntitlement(connection, entitlement);
}
</code></pre><h2>Cycript to the Rescue!</h2><p><a href="http://www.cycript.org/">Cycript</a> is awesome. It's basically a prompt that can hook into processes and accepts javascript as well as Objective-C syntax to play with memory. It requires jailbreaking your device, but <a href="https://www.twitter.com/saurik">@saurik</a> has also released a version that you can link with App Store applications for debugging :D It's perfect for prototyping, and this was how I created the first prototype that was shown on the Verge. The best part is if anything goes wrong while messing in Cycript, you can just restart the process you're hooking, therefore doing no permanent damage (hopefully! :P).</p><h2>Hosting Views Where They Probably Shouldn't Be</h2><p>By creating a SBContextHostView for the Facebook app, one can display the whole Facebook app on top of any running application. You'll also need a BKSProcessAssertion (as mentioned earlier) to keep it running.</p><pre data-language="objectivec" class="hljs"><code>SBApplication *app = [[SBApplicationController sharedInstance] applicationWithDisplayIdentifier:<span class="hljs-string">@"com.facebook.Facebook"</span>];
<span class="hljs-built_in">UIView</span> *hostView = [app1 contextHostViewForRequester:<span class="hljs-string">@"epichax1"</span> enableAndOrderFront:<span class="hljs-literal">YES</span>];
[[<span class="hljs-built_in">UIApplication</span> keyWindow] addSubview:view1];
view1.transform = <span class="hljs-built_in">CGAffineTransformMakeScale</span>(<span class="hljs-number">0.4</span>, <span class="hljs-number">0.4</span>);
view1.frame = <span class="hljs-built_in">CGRectMake</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">320</span>, <span class="hljs-number">568</span>);

BKSProcessAssertion *keepAlive = [[BKSProcessAssertion alloc] initWithPID:[app pid]
                                                                    flags:<span class="hljs-number">0xF</span>
                                                                   reason:<span class="hljs-number">7</span>
                                                                     name:<span class="hljs-string">@"epichax1"</span>
                                                              withHandler:<span class="hljs-literal">nil</span>];
</code></pre><p>Tada! Mini Facebook app! :D</p><p>For JailbreakCon 2013 I wrote a <a href="https://github.com/b3ll/JailbreakCon2013">cycript demo</a> that does all this and displays 4 applications running simultaneously on top of SpringBoard. It's hilarious to see!</p><img src="https://blog.adambell.ca/assets/f57b11616e6de4eb7805a65f2e62bd7a620e69ab7f1017c92b6fcdfa9c1a0ac0.png" alt="ALLTheApps"/><h2>Post-Cycript</h2><p>Of course there was much more work than this to actually make it usable and pleasant, such as transitions when quitting the Facebook app, and handling rotation even when the Facebook app is closed. Originally I was refreshing the app every 15-60 seconds to see if there were any new chat messages, however this shoved battery life into the ground and stomped on it. To save battery life, I hooked Facebook Messenger’s push notifications and redirected them to the Facebook app so Chat Heads update their conversations accordingly.</p><p>When all was said and done I released this hack, for free, under the name <a href="https://www.github.com/b3ll/MessageBox">MessageBox</a>. Sadly this no longer works on iOS 7 (nor the current version of the Facebook app), but I'll be sure to bring it back... someday!</p><p>Facebook Chat Heads are a wonderful way to chat. The ability to be able to chat with anyone, from inside any application, without the need to switch apps is something that isn’t new to mobile platforms (Android for example), however Chat Heads takes things to the next level. An experience that still, to this day, makes me smile when a chat head springs off one side and docks on the other.</p>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20110505-QNX-Native-Binaries-and-the-Blackberry-Playbook</guid><title>QNX, Native Binaries, and the BlackBerry PlayBook...</title><description></description><link>https://blog.adambell.ca/posts/20110505-QNX-Native-Binaries-and-the-Blackberry-Playbook</link><pubDate>Thu, 5 May 2011 10:50:00 -0400</pubDate><content:encoded><![CDATA[<p>So as you may already be aware of, RIM just released their take on how tablets should be, also known as PlayBook. The PlayBook currently runs QNX as it's operating system, with which its apps are currently built in conjunction with the Adobe AIR 2.5 SDK. Just recently at the BlackBerry World Conference, the native SDK was unveiled (it was previously seen with their Quake 3 port).</p><p>Personally, I see the Native SDK as the most interesting, as it allows one to use the device to its full potential alongside its realtime operating system (RTOS), so I started to do some digging. I poked around with the simulator for a bit, when <a href="https://www.twitter.com/stroughtonsmith">@stroughtonsmith</a> suggested I download QNX's desktop environment, otherwise named the Neutrino SDP (software development platform). What's interesting here, is the fact that it's equipped with an arm cross-compiler. What this means, is that one can already create native applications for the PlayBook, which end up being very similar to those produced with the native SDK, as well as being sandboxed.</p><p>So after <a href="http://www.qnx.com/products/evaluation/">installing QNX</a> from the DVD (can be to a virtual machine, or an actual desktop), boot it up, and login as root (no password is needed). Afterwards, simply write up an application in C/C++, and, when ready to compile, invoke the cross-compiler like so (help info <a href="http://www.qnx.com/developers/docs/6.3.2/neutrino/utilities/q/qcc.html">here</a>):</p><pre data-language="bash" class="hljs"><code>qcc -Vgcc_ntoarmle -o nativeapp nativeapp.c
</code></pre><p>To actually get this compiled application on the device, however, does require a little extra legwork... With the AIR SDK, we're given the ability to SSH into the device as "devuser", with Developer Mode enabled. First off I copied the compiled binary to the downloads folder (plug in the PlayBook, and access its shared folders). Now, even though this is on the PlayBook, it's unusable, since it doesn't have the proper permissions. Since devuser is sandboxed and limited, it can't set permissions. However, you can get around this by first setting the binary as executable, and then zipping it up:</p><pre data-language="bash" class="hljs"><code>chmod +x nativeapp
zip nativeapp.zip nativeapp
</code></pre><p>Once you've copied that zip over to the downloads folder, copy it to somewhere on the device and unzip it (I used /tmp). From there you can run the binary!</p><p>I do recommend that you guys check this out, give it a go, and at the same time, get a little practice in before the Native SDK's release. Let <a href="https://www.twitter.com/b3ll">me</a> know how it goes! QNX is looking to be an awesome system to develop with!</p><p>Download the Source <a href="http://www.adambell.ca/blog/nativeapp.c">here</a>. Download the Binary (zipped) <a href="http://www.adambell.me/blog/nativeapp.zip">here</a>.</p><img src="https://blog.adambell.ca/assets/1c939b895b66427ea3db41a0d090f749e9cbdaab552a5d155b6e4247485fbaa8.png" alt="QNX"/>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20100527-afc2-and-Finder</guid><title>afc2 and Finder</title><description></description><link>https://blog.adambell.ca/posts/20100527-afc2-and-Finder</link><pubDate>Thu, 27 May 2010 13:30:00 -0400</pubDate><content:encoded><![CDATA[<p>For a while now I've been checking up on a fabulous project entitled Disk for iPhone (formerly known as iPhoneDisk). Based on the MobileDevice API, it's a filesystem for MacFuse, which allows one to mount an iDevice in Finder. However having my iPod jailbroken I wanted to take advantage of the afc2 protocol. Low and behold, after compiling the source and installing the required daemons/extensions, the mobile<em>fs</em>util LaunchAgent's preferences can be edited to your likings. Edit the file :</p><pre data-language="undefined" class="hljs"><code>
/Library/LaunchAgents/org.thebends.iphonedisk.mobile_fs_util.plist
</code></pre><img src="https://blog.adambell.ca/assets/ba74cc03a3d546743bebed22f86b6278cda8c271ff282ceb53fa9ae308e3c158.png" alt="plist"/><p>After changing the values to your likings, simply reboot, and plug in your iDevice. In doing so (as well as having the afc2 protocol installed via Cydia), you are presented with a free and seamless way of transferring/editing files without other applications or ssh-access. Note: All symbolic links do not currently work, and clearly Finder does not exist in Windows, so for the time being this is not supported in windows...</p><p>Site and installer are <a href="http://code.google.com/p/iphonedisk/">here</a></p><img src="https://blog.adambell.ca/assets/2dc63d029caabe6c65b7cb60c06009251245df1111d8c7473aa4382948621650.png" alt="Finder"/>]]></content:encoded></item><item><guid isPermaLink="true">https://blog.adambell.ca/posts/20100520-Hello-World</guid><title>NSLog(@"hello world");</title><description></description><link>https://blog.adambell.ca/posts/20100520-Hello-World</link><pubDate>Thu, 20 May 2010 14:43:00 -0400</pubDate><content:encoded><![CDATA[<p>hello world</p>]]></content:encoded></item></channel></rss>