Apple’s Lenovo

To bring long-term value for clients, companies need to continually reinvent themselves.

This quote comes from an IBM announcement that it was selling its PC business in 2005.

IBM’s business was moving towards services, and it was less dependent on hardware sales. But it still needed hardware to provide services for its clients.

The deal let IBM focus on its future. Lenovo got the ThinkPad brand, engineering talent, and a sales channel. This was one of those rare win-win scenarios they teach in business school.

Apple is no stranger to reinventing itself. Thirty years ago, it was selling a $15,000 printer.

Laserwriter

It was a beautiful device that produced stunning output. It launched the desktop publishing revolution and established Adobe as a central figure in the software ecosystem.

And today you can’t buy a printer with an Apple logo.

Someday soon, we’ll look back wistfully at those beautiful displays Apple used to make. With the announcement of the new LG partnership and displays, we’re seeing another part of Apple’s business being outsourced.

Maybe it’s time that Apple does the same thing with the Mac Pro business described by Marco Arment.

Like IBM, Apple is in a bind. Its future and the bulk of its revenue depend on mobile devices. Yet we can’t make these products without the horsepower provided by the Mac.

Besides Apple’s own internal needs, there are many professionals creating content for mobile devices. These folks need fast and capable computers to create apps, music, and videos. We all need powerful Macs to enrich the mobile ecosystem.

John Gruber said it best, “It’s the heaviness of the Mac that allows iOS to remain light.” But will iOS pick up this heavy load by the end of this decade? I don’t see it happening with my own work.

Licensing just the operating system was a disaster for Apple. Professional customers don’t have the time to build and maintain their own Hackintoshes. Any partnership to build Mac hardware would need to be structured so that it benefits Apple, the partner, and customer alike.

Just like IBM and their clients have benefitted from Lenovo.

Adulterated Swift

There has been some discussion lately about Swift not having the dynamic features of the Objective-C runtime. Brent Simmons has been doing a great job of pointing out why this is a problem.

It’s very easy to overlook the importance of the dynamic runtime environment. Many of the things it enables happen behind the scenes. There’s no better example of this misunderstanding than a developer who says their app is “Pure Swift”.

That’s because you can’t currently write an app that only uses Swift. The purity of your code is lost as soon as you #import UIKit.

A picture’s worth a thousand words, so here’s a project that demonstrates why it’s impossible. The app itself is ridiculously simple: there’s a button, a few labels, and a single action method. It’s as “Pure Swift” as you can get.

Download Pure.zip

This project also contains an Objective-C category named NSObject+Adulterated. This category overrides two methods that lie at the heart of the dynamic runtime: -respondsToSelector: and -methodForSelector:. The normal operation of these methods is not affected; the only additional functionality is some logging to the console when they’re used. Other than being in the bridging header, the code is not used directly by the app.

When you run the app, you’ll immediately see all the places where Swift is not being used. Pretty much everything you take for granted in your app is using the dynamic runtime. Layout, drawing, animation, and event handling are all dependent on something that Swift doesn’t have yet.

Of course, you’ll immediately say, “This isn’t Swift’s problem! Just rewrite the frameworks!”

And that is exactly the point I’m trying to make.

The community around Swift’s evolution is amazing. The language is improving quickly and dramatically thanks to talented developers inside and outside of Apple. It’s a remarkable open source project.

My concern is that there isn’t a corresponding discussion about the things we’re going to build with this new language. As you’ve just seen, frameworks are important, yet there is no uikit-evolution mailing list. There is an imbalance between the tool and the craft.

I’m guessing that part of this problem lies within Apple itself. There are plenty of developers in Cupertino who have built large applications and the frameworks that they use. I’m absolutely certain that this subject has been discussed in detail by some very smart folks. And they, of course, can’t talk about internal projects.

My suggestion for the folks on the Swift project is to be a little more forthcoming about future plans with frameworks and other infrastructure besides the language itself. It’s a big piece of a puzzle that long-time app developers want and need.

A lot of hand-wringing could be ameliorated with a simple “Yep, we’re working on it.”

Strapped In

A lot has happened since I purchased my Apple Watch on April 10th, 2015. One unexpected aspect to owning this device is my fascination with watch bands:

Apple Watch Bands

My current collection of watch bands. And no, the watch isn’t upside down.

From left to right, in order of date purchased:

  • Sport Model with Blue Band ($400) – I picked the aluminum watch with a blue band because I knew it would be spending a lot of time in the water. To date, I’ve used it 110 times for over 35 hours of swimming.
  • Milanese Loop ($150) – I was intrigued by this band as soon as I saw it during the video at the product announcement. I love how the metal feels a lot like fabric. It also dresses up the utilitarian Sport model so it doesn’t look out of place when I’m someplace nice.
  • Black & Silver Nylon ($30) – This NATO-style band from Clockwork Synergy popped up on my Twitter timeline thanks to my pal Rob Rhyne. I love that it dresses up the watch and is waterproof.
  • Red Sport ($50) – When Apple started selling additional colors for the sport bands, getting one in my favorite color was a no-brainer. I also like that a little of my purchase goes to a worthwhile charity.
  • Orange Silicone ($20) – This band by MoKo was another recommendation from Twitter by Neven Mrgan. To me, the most interesting thing about this band is that it shows why Apple went with fluoroelastomer for their bands: it’s stiffer and “breathes” better than silicone.
  • Black Goat Leather ($200) – The leather bands from Apple are nice, but I prefer the classic look of this one from Lucrin. The company also offers a huge range of colors: my wife loves the dark green one I gave at Christmas.

In this survey of my growing collection, there’s an interesting datapoint: the value of these bands ($450) exceeds the cost of the watch itself ($400).

If Apple decides to change the interchange mechanism in some future version of the watch, I will have very little desire to upgrade. As I continue to “work in” my leather band, I hope I’ll be using them for a long time.

The New iPod

Something tells me that there were a lot of Apple Watches under the tree this year:

Clicker Downloads for December 2015

That graph shows the last month of downloads for my free Clicker app for watchOS. Since this app does nothing on an iPhone or iPad, the only reason to get it is if you have a new watch.

Many of us, myself included, originally thought of the Apple Watch as a device in and of itself. But the more I use the computer on my wrist, the more it feels like a satellite to the computer that’s sitting in my pocket.

Accessories have always made great gifts for folks who love their computers. Giving the watch as a gift is a perfect option for someone who’s always playing around with the apps on their iPhone. Just like the iPod was an ideal match for someone who loved playing music on their desktop computer.

Code Signing in El Capitan

After releasing a update for xScope with fixes for El Capitan, I launched the app on a fresh install of the OS and was greeted by this dialog:

xScope download blocked by Gatekeeper

I had tested the build on Yosemite, and it passed without any problems:

$ spctl -a -v ~/Downloads/xScope.app
/Users/craig/Downloads/xScope.app: accepted
source=Developer ID

Clearly there is something new with Gatekeeper in El Capitan. As the author of a tool used by so many early adopters, I often get the job of figuring out what’s new with code signing. Lucky me :-)

I quickly filed a Radar about the problem. This led to feedback from Apple that helped me understand why Gatekeeper rejected my app. The change in El Capitan has the potential to affect a lot of developers (including the big guys), so it’s time to share what I learned.

(If you’re one of those people that claims that “Radar never works”, then that last paragraph just proved you wrong.)

When I ran the spctl tool on El Capitan, I saw an “obsolete resource envelope” error:

$ spctl -a -v --raw xScope.app
xScope.app: rejected
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>assessment:authority</key>
	<dict>
		<key>assessment:authority:source</key>
		<string>obsolete resource envelope</string>
		<key>assessment:authority:weak</key>
		<true/>
	</dict>
	<key>assessment:cserror</key>
	<integer>-67003</integer>
	<key>assessment:remote</key>
	<true/>
	<key>assessment:verdict</key>
	<false/>
</dict>
</plist>

This is a sign that there’s a problem with the code signature. In the past, this has been caused by a change to the signature version number (from 1 to 2). In El Capitan, the cause is more stringent code signature checks.

(Note that I also used the --raw option. According to the man page, “This is useful … to access newly invented assessment aspects that spctl does not yet know about.”)

The functional equivalent to spctl -a is the following codesign command. The --deep option checks any embedded code (such as the Sparkle framework.) Note that --strict is a new option in El Capitan (so new, that it’s not documented yet):

$ codesign --verbose=4 --deep --strict xScope.app
--prepared:/Users/craig/Downloads/xScope.app/Contents/Frameworks/Sparkle.framework/Versions/Current/.
xScope.app: unknown error -67003=fffffffffffefa45
In subcomponent: /Users/craig/Downloads/xScope.app/Contents/Frameworks/Sparkle.framework
file modified: …/Sparkle.framework/Versions/Current/Resources/fr.lproj/fr.lproj
file modified: …/Sparkle.framework/Versions/Current/Resources/fr_CA.lproj

Gatekeeper is rejecting xScope because it thinks some files in Sparkle have been modified after the code signature was generated. This seemed unlikely since the frameworks are code signed during the copy build phase and our automated build process creates a ZIP archive just after the app bundle is created.

I dug around in the application package contents and saw the following:

$ ls -ls Sparkle.framework/Versions/Current/Resources/fr_CA.lproj 
8 lrwxr-xr-x@ 1 craig  staff  84 Jul 22 12:31 Sparkle.framework/Versions/Current/Resources/fr_CA.lproj
  -> /Users/andym/Development/Build Products/Release/Sparkle.framework/Resources/fr.lproj
$ ls -ls Sparkle.framework/Versions/Current/Resources/fr.lproj/fr.lproj 
8 lrwxr-xr-x@ 1 craig  staff  84 Jul 22 12:31 Sparkle.framework/Versions/Current/Resources/fr.lproj/fr.lproj
  -> /Users/andym/Development/Build Products/Release/Sparkle.framework/Resources/fr.lproj

Well, well, well.

Gatekeeper rejected the app because I’m using Sparkle 1.5b6. The framework has symlinks to paths on a Mac that I doubt Andy Matuschak uses anymore. That’s completely reasonable: those symlinks could just as easily point to something a lot more damaging than a non-existent directory.

The --strict option currently checks the validity of symlinks. You can point a symlink at a path in your own application package, /System or /Library, but nowhere else. The code signing rules also allow language translations to be removed, but if they are present they must be unmodified.

The quick fix for this problem was to remove the invalid symlinks; a new build passes the same check without any problems:

$ codesign --verbose=4 --deep --strict xScope.app
--prepared:/Users/craig/Downloads/xScope.app/Contents/Frameworks/Sparkle.framework/Versions/Current/.
--validated:/Users/craig/Downloads/xScope.app/Contents/Frameworks/Sparkle.framework/Versions/Current/.
--prepared:/Users/craig/Downloads/xScope.app/Contents/Frameworks/YAML.framework/Versions/Current/.
--validated:/Users/craig/Downloads/xScope.app/Contents/Frameworks/YAML.framework/Versions/Current/.
xScope.app: valid on disk
xScope.app: satisfies its Designated Requirement

A better solution is to update to a newer version of Sparkle. The project was dormant from 2008 to 2014, so many of us didn’t realize that the team behind the project is doing regular updates again.

Many of your customers will be downloading and running your app on the El Capitan public beta: you should do the codesign --deep --strict check on any new releases to avoid customer support issues. It’s also likely that a similar check will be performed for you when the Mac App Store eventually allows submissions for 10.11.

And let’s get together again when 10.12 is released! In the meantime, enjoy this new release of xScope on Apple’s new release of OS X.