Edenwaith Blog
25th March 2017 | Edenwaith
2017 will be a year of renewal, which will focus on rebuilding the website and certain products.
Website
The last major set of website improvements date back to 2009, well before responsive design was a standard to address the browsing capabilities for smart phones and tablets, in addition to their desktop counterparts. I've been researching a number of new methods for the fourth major redesign of the Edenwaith website. I've been heavily favoring some form of static site generation to display the various projects hosted here, plus allow for a decent blogging solution. This is still in the early stages and will require some experimentation to determine what will work best for this site's needs.
Until the day that Edenwaith 4.0 is live, I have introduced a couple of new design elements to the current site to try out a couple of new ideas.
- Removed the Company section and replaced it with the About section.
- Updated the Products and Downloads pages.
- Redesigned the home page so it is more responsive and readable on mobile devices.
- Added GitHub, Twitter, and Contact icons in the page footer. Makes use of FontAwesome.
- Added higher resolution graphics for a better appearance on Retina-level displays.
EdenList for iOS 2.0
EdenList for iOS began as my first project for the iPhone back in 2009. In the past eight years, a lot has changed in the realm of iOS development. I have incrementally improved this app on a yearly basis, but its development has finally reached a point where the original foundation is too unstable and archaic to be viable in this rapidly mutating environment. Gone will be the Objective-C, XIBs, and manually managed memory, which will be replaced by Swift, Storyboards, and ARC (amongst many of the various other refinements).
Permanent Eraser
There are still a handful of features I'd like to complete during the 2.x lifespan of Permanent Eraser. Version 2.7.1 was released last December and plans are in the works for PE 2.7.2 and 2.8. After that, things are very much up in the air, but there are some interesting paths which Permanent Eraser might travel in the future.
29th January 2017 | Programming
The following are a collection of useful tips and tricks I've developed over the past year to help keep things neat and tidy in my development environment.
Free up space taken by Xcode
The problem: Xcode is a huge space hog, not only in the size of the app, but with all of the detritus which is left about from old archives, simulators, and derived data. This often results in my work computer displaying low space warnings.
- Run a disk sweeper to find where the most space is being taken and then delete files from:
- Archives:
~/Library/Developer/Xcode/Archives
- Derived data:
~/Library/Developer/Xcode/DerivedData
- Device logs:
~/Library/Developer/Xcode/iOS Device Logs
- Old simulators:
~/Library/Developer/Xcode/iOS DeviceSupport
- Really old simulators:
~/Library/Application Support/iPhone Simulator
- Old documentation:
~/Library/Developer/Shared/Documentation/DocSets
- Remove old simulators and devices from
~/Library/Developer/CoreSimulator/Devices
with the command: xcrun simctl delete unavailable
/Developer/Platforms/iPhoneSimulator.platform-old
/Developer/Platforms/iPhoneOS.platform/DeviceSupport
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk
- The entire
/Developer
folder
- Reboot your computer to free up memory
Clean up old local git branches
The problem: Without regular maintenance, your local git repository will become a cluttered mess of old branches. Before cleaning your local git branches, your repository might look like this:
$ git branch --merged
Bugfix/FOOBAR-1000
Bugfix/FOOBAR-1007
Bugfix/FOOBAR-1015
Bugfix/FOOBAR-1026
Bugfix/FOOBAR-1057
Bugfix/FOOBAR-1058
Bugfix/FOOBAR-1060
Bugfix/FOOBAR-1061
Bugfix/FOOBAR-1062
Bugfix/FOOBAR-1099
Bugfix/FOOBAR-1106
Bugfix/FOOBAR-1132
Bugfix/FOOBAR-1139
Bugfix/FOOBAR-1141
Bugfix/FOOBAR-1151
Bugfix/FOOBAR-1155
Bugfix/FOOBAR-1157
Bugfix/FOOBAR-1168
Bugfix/FOOBAR-1172
Bugfix/FOOBAR-1181
Bugfix/FOOBAR-1206
Bugfix/FOOBAR-1242
Bugfix/FOOBAR-1250
Bugfix/FOOBAR-953
Bugfix/FOOBAR-997
Bugfix/FOOBAR-998
* develop
feature/FOOBAR-1200
feature/FOOBAR-142
feature/FOOBAR-215
feature/FOOBAR-221
feature/FOOBAR-241
feature/FOOBAR-242
feature/FOOBAR-261
feature/FOOBAR-277
feature/FOOBAR-287
feature/FOOBAR-778
feature/FOOBAR-798
feature/FOOBAR-896
feature/FOOBAR-90
feature/FOOBAR-90-merge
feature/FOOBAR-906
feature/FOOBAR-960
feature/stores/search
master
Using a git/grep/xargs concoction, you can quickly clean this up. Delete all local merged branches, except for the branches named master
or develop
.
git branch --merged | grep -v '\*\|master\|develop' | xargs -n 1 git branch -d
This will result in local branches being deleted, with output similar to this:
Deleted branch Bugfix/FOOBAR-1000 (was ab382ed).
Deleted branch Bugfix/FOOBAR-1007 (was 493b17b).
Deleted branch Bugfix/FOOBAR-1015 (was e7e1f6a).
Deleted branch Bugfix/FOOBAR-1026 (was 19b6d62).
Deleted branch Bugfix/FOOBAR-1057 (was 8f06d42).
Deleted branch Bugfix/FOOBAR-1058 (was e285fde).
Deleted branch Bugfix/FOOBAR-1060 (was 96318b5).
Deleted branch Bugfix/FOOBAR-1061 (was a84bcac).
Deleted branch Bugfix/FOOBAR-1062 (was 2b7310c).
Deleted branch Bugfix/FOOBAR-1099 (was 8260dd0).
Deleted branch Bugfix/FOOBAR-1106 (was cf401f2).
Deleted branch Bugfix/FOOBAR-1132 (was 4af883c).
Deleted branch Bugfix/FOOBAR-1139 (was 3f89c9b).
Deleted branch Bugfix/FOOBAR-1141 (was 13763d0).
Deleted branch Bugfix/FOOBAR-1151 (was 6ca43c4).
Deleted branch Bugfix/FOOBAR-1155 (was b020c21).
Deleted branch Bugfix/FOOBAR-1157 (was 903dee7).
Deleted branch Bugfix/FOOBAR-1168 (was abb20b6).
.
.
.
Perform one more check to ensure that your local repository has been cleaned up:
$ git branch --merged
* develop
feature/FOOBAR-242
master
synx — Organize an Xcode project's file system
The problem: The file system structure of your project does not match up to the project's Xcode structure. If not properly handled early on in a project's life cycle, the organization between the project and it's matching file system will quickly become out of sync and result in a massive dump of unorganized files.
The idea to write a script seemed like a good weekend project, but fortunately this problem has already been solved. Enter synx
, a command-line tool that reorganizes your Xcode project folder to match your Xcode groups.

To install: gem install synx
To run: synx /path/to/project.xcodeproj
...and viola!...er...ah....Voilá! No more unorganized file system structure.
Taking a simulator screenshot from the command line
The problem: As of Xcode 8, trying to take a screenshot of the iOS simulator using the keyboard shortcut ⌘-S
will result in the simulator crashing. This issue occurs only with OS X El Capitan and Xcode 8, but not with macOS Sierra and Xcode 8.
From the command line, run: xcrun simctl io booted screenshot
I created a small shell script named tss.sh
(short for Take Simulator Screenshot) which switches to the Desktop, takes the screenshot of the running simulator, saves the picture to the Desktop, then switches back to the original directory. I then created an alias so I only need to type tss
from the Terminal to take a screenshot.
To make this even easier, create an Automator Workflow service to run the shell script and then attach a keyboard shortcut to it. This method circumvents event needing to go to the command line to call the script. Press ⇧-⌘-5 and a screenshot is taken of the simulator.
References
10th September 2016 | Programming
I recently came across TarDisk, an interesting combination of hardware and software wizardry which uses the often unused SDXC slot on a Mac laptop to increase the total storage space. Considering that I am constantly running out of drive space on my work computer, this struck me as a very useful thing to assuage the perpetual freespace problem, but I was even more intrigued by the associated Pear software which combines the laptop's and the TarDisk's space into one logical unit, much like the Fusion drive in modern iMacs which take advantage of the speed of an SSD and the cheapness and spaciousness of HHD. I have not found any specifics on how Pear manages to merge the SD card with the computer's SSD, but I would not be surprised if it is making use of OS X's Core Storage technology to combine multiple disks into a single logical volume.
This got me wondering if it would be possible to do something similar by combining two connected USB disks into a single drive by using Core Storage. Indeed, this is possible. To do so involves running two commands from the command line using the diskutil
utility.
diskutil coreStorage create LOGICAL_VOL_GROUP_NAME DRIVE_1 DRIVE_2
diskutil coreStorage createVolume lvgUUID type name size
LOGICAL_VOL_GROUP_NAME
is the name you wish to assign to the new volume. DRIVE_1
and DRIVE_2
are the paths to the drives. Use the command diskutil list
to get the path name of the drives (e.g. /dev/disk2
). lvgUUID
is returned after creating the new group. The output should be similar to the following:
diskutil coreStorage create FusedUSB /dev/disk4 /dev/disk5
Started CoreStorage operation
Unmounting disk4
Repartitioning disk4
Unmounting disk
Creating the partition map
Rediscovering disk4
Adding disk4s1 to Logical Volume Group
Unmounting disk5
Repartitioning disk5
Unmounting disk
Creating the partition map
Rediscovering disk5
Adding disk5s1 to Logical Volume Group
Creating Core Storage Logical Volume Group
Switching disk4s1 to Core Storage
Switching disk5s1 to Core Storage
Waiting for Logical Volume Group to appear
Discovered new Logical Volume Group "BF21D233-99CC-8AD9-853D-4339E765UI09"
Core Storage LVG UUID: BF21D233-99CC-8AD9-853D-4339E765UI09
Example
diskutil coreStorage create FusedUSB /dev/disk4 /dev/disk5
diskutil coreStorage createVolume BF21D233-99CC-8AD9-853D-4339E765UI09 jhfs+ FusedUSB 100%
To revert these changes, run the command
diskutil coreStorage delete lvgUUID
. Keep in mind that creating and deleting Core Storage volumes is a destructive process and will delete any content that is already existing on the drives.
References
9th July 2016 | Apple
This year I was finally fortunate enough to attend WWDC, and following the advice of many others, I am including my own thoughts, tips and tricks about attending WWDC for the first time.
Finding a Hotel
Lodging in a large city is not cheap, and San Francisco (already renown for being one of the most expensive places to live in the U.S.) was no different. Trying to find anything even semi-affordable in downtown S.F. is a difficult task, and even more so to find something in a nicer area. Read up on reviews of the various hotels first, and stay out of the Tenderloin district. I will repeat that: Stay out of the Tenderloin district.
The Keynote
Historically, one wanted to line up for the Keynote as early as possible so one could get a seat in the main conference room where the Keynote was being held, otherwise you would be relegated to an overflow room. This year the Keynote was moved to the Bill Graham Civic Center, which was able to seat all 5000 attendees, journalists and special guests. It was packed, but this probably worked a lot better than trying to herd everyone into Moscone West for the Keynote.
I arrived at the Bill Graham Civic Center around 5:55. Just 10 minutes later, a decent sized line showed up behind me. Two lines were formed, one for the ground level and one for the upper level. I ended up on the upper level, but the giant screens helped show what was going on and the acoustics weren’t too bad.
Food
Others have reported that in the past meals were a catered affair. With 5000 people to feed, though, it works best to have the pre-packaged meals so people can just quickly pick up a meal from a table and then find a place to sit and eat. Breakfast generally consisted of pastries, muffins, donuts and bagels with juice and coffee. Lunch often came in three varieties such as chicken, beef or vegetarian (sandwiches, salads, and some form of desert). Snacks and beverages were also available between meals. There was enough food, and sometimes there was enough left over from my lunch that it made for a good dinner. If you want a coffee, there are plenty of Starbucks around, including two just a block away from Moscone West. Interestingly enough, I never came across a single McDonalds during my stay in San Francisco, so no iced coffees from there.
Weather
San Francisco's weather is reminiscent of being in the mountains. It tends to be cool in the mornings and evenings, but will warm up during the middle of the day. During the week of the conference, temperatures ranged from 13°C to 18°C (I'll leave it as an exercise to the reader to convert those temperatures to Fahrenheit). I was glad I was given an extra jacket when I checked in, since I needed it on Monday morning while waiting in line for the Keynote.
Sight Seeing
Most of my time was spent attending the conference, but I did manage to reserve a couple of hours to check out some of the more interesting and pleasant parts of downtown San Francisco.
- Apple Store: I visited the new Apple Store off of Union Square, which is certainly quite different from all of the other Apple Stores I've visited.
- Trolley + Fisherman's Wharf : San Francisco is famous for its trolleys, which are now more for nostalgia and entertainment than an expansive form of public transportation. When I wasn't walking, I tended to either take a taxi or the BART (from SFO to downtown) to get around. Fisherman's Wharf reminded me of Chicago's Navy Pier — pretty much a large tourist trap, but with crab sandwiches.
- City Bus Tour : This was an excellent way to see most of the highlights of the city, including going across the Golden Gate Bridge. Recommended method of getting around to see the sights.
Conclusion
Attending WWDC was a magnificent experience. I’m not certain if I’ll be able to ever attend again, so it was wonderful to have the chance to attend this conference. Having all of the WWDC sessions available on-line is a great resource, but it just isn’t quite the same as being there in person where you have an entire week dedicated to watching these sessions and (trying to) absorb as much new knowledge as possible. In the past, I might watch a handful of sessions on the internet, but by being at the conference it allowed me to see a lot more of the sessions, including some I may not have bothered watching. Some of the sessions were great, some were surprisingly more interesting than expected, and a few were incredibly deep and complex. The information is invaluable, but the networking is what truly makes WWDC a fun experience. Meet other developers from all over the world (and there is plenty of chance to meet new people when you stand in various lines throughout the day) or perhaps even bump into a semi-famous face or two.
22nd May 2016 | Programming
The Goal
Create a recurring maintenance task that will move all screenshots from the Mac's Desktop into a designated folder each day.
The Options
I looked at a number of different options to automate this maintenance task. I needed something non-obtrusive, straightforward and flexible.
- Calendar + Automator — This is the more graphical approach, but the downside is seeing repeating events littering up the Calendar. I prefer to keep the Calendar as clean as possible.
- Folder Actions — I've used Automator to create a Folder Action on other folders before, such as the Downloads folder to place new files in specific locations, but I needed something that would only run once a day, not every time a new file was added to a folder.
- cron — Having coming from a UNIX background, I knew of
cron
. A little research on this topic tended to recommend using launchd
instead for Mac OS X.
- launchd —
launchd
fit the bill for what I was looking for. It had the flexibility to allow me to run a given script on a daily basis.
The Code
In this example, I created a plist list file named local.cleanupdesktop.plist
and placed it into the directory ~/Library/LaunchAgents
. This particular plist configuration displays just a small portion of what is possible. In this example, it runs the script cleanupdesktop.sh
each day at 9:30. For a more comprehensive list of what options are available, check the comprehensive resources at launchd.info.
The cleanupdesktop.sh
script is a small bash script which searches for any screenshots which are on the Desktop and places them into the Screenshots folder. This particular script will take screenshots from the keyboard shortcut or from screenshots taken from the iOS Simulator.
Another Example
The next example is even simpler which has everything contained within the plist file. This launch agent will display an alert every weekday at 5 p.m. (17:00) as a handy reminder. The code passes in program arguments, which effectively invokes an Applescript command: osascript -e 'display notification "Update your tickets" with title "Reminder" sound name "Sosumi"'
.
Installing the Launch Agent
To get these new launch agents to run, either log out and then log back in to your account, or the launch agent can be manually loaded from the command line using the launchctl
utility:
launchctl load -w ~/Library/LaunchAgents/local.cleanupdesktop.plist
Likewise, if you want to unload the launch agent, use the command:
launchctl unload -w ~/Library/LaunchAgents/local.cleanupdesktop.plist
References
19th May 2016 | Programming
On a typical day, I might have a dozen Safari windows open, each replete with its own set of tabs. With each tab sandboxed in its own process, this can result in a bevy of running tasks on the system. As an interesting (and useful) exercise, I wanted to write a small script which would quickly tell me how many open tabs I had in Safari.
The most obvious solution for my needs to be able to interact with Mac applications, yet retain the flexibility of a programming language is AppleScript. AppleScript is just another one of a multitude of languages I've dabbled with over the years, going as far back as the System 7 days. I pick up AppleScript every now and again when the appropriate need arises, but I find myself needing to relearn its capabilities. AppleScript has high readability with its English-like syntax, but it makes for some esoteric writing at times, to ensure that the proper syntax is being used.
The goal is straightforward: Grab every Safari window, total up the number of tabs, and return the result. In this particular example, I had the script print out the result so I could run it from the command line using the osascript
command.
The Code for Safari
Running the script
$ osascript CountOpenSafariTabs.scpt
There are 112 Safari tabs open.
To further simplify things, I added the following alias to my .bash_profile
file, so I only need to type counttabs
in the Terminal to get the desired answer:
alias counttabs='osascript ~/Projects/scripts/CountOpenSafariTabs.scpt'
The Code for Chrome
2 December 2019 Update: The following is a similar AppleScript for Google Chrome.
References
15th May 2016 | Edenwaith
A couple of quick items about the year so far and a brief look ahead.
EdenList 1.2.3
EdenList for iOS was updated in April with several UI and UX improvements. In accordance to recent trends, the App Store approval time for this app had improved over past experiences to just three days. In the past, review times were generally between seven to ten days.
EdenGraph Retired
After ten years of inactivity, the decision has been made to officially retire EdenGraph. The source code for this project is available on GitHub.
The Mysterious Case of the Expired Certificate
Another talk about the fun and joys of dealing (translation: struggling and fighting) with Xcode, code signing and provisioning profiles. The summary of the talk was about the Apple Worldwide Developer Relations Certification Authority certificate expiring on 14 February 2016, which resulted in a number of bizarre behaviors. Delete the old certificate from your Keychain and update to the latest certificate. We'll be all set until 7 February 2023, when the current certificate expires.
Tip : Disabling Auto-launching For Android Phones on a Mac
Whenever I would plug in the HTC One (M7) into a Mac, a couple of apps might try and start up. This became quite annoying, so here are a couple of tips to disable Android File Transfer and Photos from launching when the HTC One is connected.
- To disable Google's Android File Transfer from auto-launching: Go to your Mac's System Preferences > Users & Groups > Login Items tab and remove Android File Transfer Agent from the list. This is a helper app which watches for new devices being connected to the computer.
- To disable Apple's Photos from auto-launching, type in the following command in Terminal:
defaults -currentHost write com.apple.ImageCapture disableHotPlug -bool YES
2016 : On and On...
The plans for the remainder of this year are fairly slim, but will mainly focus on an update to Permanent Eraser and rebuilding the Edenwaith website.
26th December 2015 | Permanent Eraser
As mentioned earlier this year, the newly released Permanent Eraser 2.7 will (likely) be the final major hurrah for the 2.x line. New features, fixes and improvements in this release include:
- New contextual menu plug-in for Mac OS X 10.5 Leopard.
- Increased app responsiveness while preparing to erase the Trash.
- Fixed a Retina UI issue on Yosemite.
- Fixed UI issues for non-English localizations.
- Tested and verified for OS X 10.11 El Capitan.
The biggest new feature is a new contextual menu plug-in for pre-Snow Leopard versions of Mac OS X. The plug-in has been tested on both Tiger and Leopard (it may work on even earlier versions of Mac OS X, but this has not been verified). Even though Permanent Eraser 2.7 does not run on Tiger, the plug-in can be downloaded and installed into your account's ~/Library/Contextual Menu Items/
folder. If the folder Contextual Menu Items
does not exist, create the folder first, then copy the file EraseCMI.plugin
into the folder. Then restart your Finder by either restarting your computer or typing the following command into the Terminal: killall Finder
This new plug-in was more of an interesting exercise to create the type of plug-in from that would have been written ten years ago, during the days when Finder was still based off of Carbon instead of Cocoa. The result is a faster and more integrated solution for older versions of Mac OS X, rather than using the slower Automator workflow.
The latest version of OS X (10.11 El Capitan) finally removed the Secure Empty Trash and Erase Free Space features from Finder and Disk Utility, respectively. As detailed in the security note CVE-2015-5901:
Finder
Available for: Mac OS X v10.6.8 and later
Impact: The “Secure Empty Trash” feature may not securely delete files placed in the Trash
Description: An issue existed in guaranteeing secure deletion of Trash files on some systems, such as those with flash storage. This issue was addressed by removing the “Secure Empty Trash” option.
CVE-ID
CVE-2015-5901 : Apple
Due to the way that Solid State Drives rewrite data to the disk using wear leveling techniques, it is not possible to repeatedly write over data like it is with mechanical hard drives. In 2015, the only Apple computers which even come with the older hard drives (whether stand alone or as part of a Fusion Drive) are the iMac, the Mac mini, and a 3 year old version of the 13" Mac Book Pro. Even the Mac Pro has eschewed the older technology in favor of the faster speeds of SSD. Since a majority of Apple's computers which are sold these days are laptops, there is less and less need for secure file shredders. If you are using an SSD, the recommended way to protect your data is to encrypt the drive by turning on FileVault.
Does this mean that this is the end of Permanent Eraser? Not necessarily. Various ideas and prototypes for the next version of this app have been floating around for several years, but with the shift in storage technology, Permanent Eraser may also need to shift to address new needs — otherwise, the app will slowly become obsolete as it would cater to a continually declining niche market.
2nd July 2015 | Apple
When the iPhone 5s came out, I wanted to love it, to be enamored by its advancements. I really did, but despite my desire to yearn for it, the longing and admiration just wasn't there. The iPhone 5s is a fine phone, but the level of improvements over the iPhone 4S just were not enough to convince me to immediately upgrade. There were some niceties such as the addition of LTE and Touch ID, but those still weren't enough. Much of the low hanging fruit had already been plucked, and the yearly advancements in mobile technologies were tapering off.
Eager to find something fresh, my gaze extend outside of the Apple ecosphere. Many Android phones are slabs of poorly designed plastic, lacking the level of precision and quality which I was accustomed to with Apple products. One product which did catch my eye was the 2013 edition of the HTC One (M7).
I've used two versions of the M7, a silver Google Play edition and a metallic blue Verizon version. Externally, the phones are nearly identical except for the coloring and the addition of a carrier logo on the Verizon phone. The phone is a good size (quite a bit larger than the iPhone 4S), and feels very solid. However, one thing I missed about iOS was having a Home button to wake up the phone. Otherwise, the build quality is excellent.
The Google Play edition resolved one of Android's biggest hurdles by being able to upgrade to the latest version of KitKat (Android 4.4), whereas the Verizon version was restricted to version 4.2.2, with no word that Verizon has any plans on updating the software on the phone. The only work around to get future versions of Android looks like to root the device and upgrade it manually. This may not be the worst idea, since the Verizon M7 comes cluttered with a bunch of their carrier-branded crapware (which can't be manually uninstalled, either), so wiping the device and upgrading might be a worthwhile endeavor. I used these phones as testing devices (no SIM cards), which need to be put into Airplane Mode to get them to work properly with Wi-Fi. On the software front, getting the Google Play version of a device is certainly the way to go. No corporate branding, no unwanted crapware, and an easy upgrade path.
In September 2014, Apple announced the yearly update to the iPhone line: the iPhone 6 and iPhone 6 Plus. The iPhone 6 was Apple phone I was hoping for that would impress me again and make upgrading worthwhile. After using my trusty workhorse of an iPhone 4S for three years, trading up to the iPhone 6 came with numerous perks.
- Larger 4.7" screen for easier typing and reading
- 128 GB of storage
- NFC for Apple Pay
- Touch ID
- LTE networking
- General hardware improvements in the camera, speed, memory
The iPhone 6 line builds upon its predecessors, so some of these features had already been around for a year or few, but the larger screen size and expanded storage space were great additions. The 3.5" screen on the first several iterations of the iPhone looked astounding in comparison to the bevy of phones it supplanted, but it began to look diminutive in comparison to some of the newer Android phones, such as the HTC One's gorgeous 4.7" screen.
The iPhone 6 is an amazing device, one which I hope to be using well into 2017. The two year cycle of replacing phones might become more a thing of the past as the hardware and software improves to a point where these devices' lifespans can reach out to 3+ years (barring the usual accidents). Personal computers in the 1980s had a life expectancy of around three years before they became too antiquated to run the latest software. The computers built in the 21st century have reached a point where they can easily reach 5, 7, or more years of use. The youngest of the three Macs I use regularly at home is 8 and the oldest is now a dozen years in age.
Google's and Apple's developer conferences, Google I/O and WWDC respectively, are used as the platforms to announce their latest advancements and things to look forward to in the coming year. Normally these conferences bring about some interesting changes, especially in the realm of mobile technologies, but 2015 was quite the bust for both conferences. Aside from the Google Photos service, Google I/O elicited not much more than a yawn from me. I was hoping that WWDC would hold more promise.
The potential was there, but it was not met. Aside from the now yearly upgrades to OS X and iOS, there was the introduction of Apple Music, which was only marginally more interesting to me than Google Photos. For the past three years I've been hoping for an upgrade to the Apple TV that would be amazing enough that it would finally convince the rest of my family to cut the TV cable. No announcement yet, but there is always hope that something like this is in the works.
The iPhone in 2007 heralded the beginning of the current generation of smart phones, turning a device with twelve buttons into an amazing computer that fits into your pocket. The biggest shortcomings have been addressed and now Google and Apple are grasping to find interesting and important problems to tackle in the mobile space. We have reached a plateau in this space, where the annual leaps in technology are no longer being met. This is a lull in the storm for the time being, but things will eventually be churned up again, bringing about the next set of technological advancements, whether that is in mobile or another area altogether.
29th April 2015 | Permanent Eraser
Each new version of OS X brings changes, which often prompts software makers to update their own products to ensure that things work properly on the new system. Sometimes the changes are minor and other times they are quite severe. This article will focus on two areas, Gestalt and code signing, which required some additional work to get Permanent Eraser 2.6.3 to work properly with Apple's desktop OS of 2014 — Yosemite.
Gestalt + Yosemite
There have been numerous ways to determine the operating system version on OS X, but it hasn't been until recently that Apple provided a sanctioned way in Objective-C (and Swift) with the inclusion of NSProcessInfo's operatingSystemVersion
method. This is a welcome, albeit highly belated, addition to the Cocoa framework.
Before the inclusion of the operatingSystemVersion
method, programmers used a variety of methods to determine the operating system's version, including a mainstay which harkens back to the pre-Cocoa days — the Gestalt Manager. Up until Yosemite (aka OS X 10.10), the following code snippet worked pretty well.
SInt32 osVersion;
Gestalt(gestaltSystemVersion, (SInt32 *) &osVersion); // Set OS Version
if (osVersion >= 0x00001060) { // Snow Leopard (10.6) or later
...
}
Unfortunately, with a system version like 10.10.0, we have run out of space using this old format, which results in warnings such as the following to appear:
WARNING: The Gestalt selector gestaltSystemVersion is returning 10.9.0 instead of 10.10.0. Use NSProcessInfo's operatingSystemVersion property to get correct system version number.
The problem which is encountered is when either the minor or patch numbers exceed the number 9, so the version of Mac OS X 10.4.11 would be returned as 10.4.9 or 10.10.3 would be returned as 10.9.3. Years ago, some Adobe installers encountered an error when trying to install on Mac OS X 10.4.10 or 10.4.11, thinking that it was an earlier version of Tiger (Adobe InDesign 4.0.5 does no longer start up). The problem now results in the returned OS version has run out of space to properly represent the system version for Yosemite.
The work around for this problem was to make use of a back port which will use the latest methods, but will fallback to another method for earlier versions of OS X. The replacement for the Gestalt call I used was Jake Petroules' CocoaBackports, which checks if methods like operatingSystemVersion
and isOperatingSystemAtLeastVersion
are available. If not, swizzle the methods and use the custom methods. The updated code now looks like this:
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 6, 0}] == YES) {
...
}
Code Signing + Yosemite
A year ago I detailed the process I took to code sign Permanent Eraser to work with Gatekeeper on Mountain Lion and Mavericks. However, when developing Permanent Eraser 2.6.3, I encountered the following error when trying to launch the app on Yosemite.
So what happened?! This was working before! Let's do a quick codesign verification to see what is happening. If your app has been signed with an older version of codesign
, you will see the following message if you verify the package with current versions of OS X:
codesign --verify --verbose=4 MyGreatApp.app
MyGreatApp.app: resource envelope is obsolete (version 1 signature)
If everything is good, then it might look more like this:
codesign --verify --verbose=4 MyGreatApp.app
--prepared:MyGreatApp.app/Contents/Library/Automator/Foo.action
--validated:MyGreatApp.app/Contents/Library/Automator/Foo.action
--prepared:MyGreatApp.app/Contents/PlugIns/Bar.workflow
--validated:MyGreatApp.app/Contents/PlugIns/Bar.workflow
--prepared:MyGreatApp.app/Contents/PlugIns/Baz.workflow
--validated:MyGreatApp.app/Contents/PlugIns/Baz.workflow
MyGreatApp.app: valid on disk
MyGreatApp.app: satisfies its Designated Requirement
Or for the more succinct version:
codesign --verify -v MyGreatApp.app
MyGreatApp.app: valid on disk
MyGreatApp.app: satisfies its Designated Requirement
If the app hasn't been signed at all, then you will see a response like this:
codesign --verify --verbose=4 MyOldApp.app
MyOldApp.app: code object is not signed at all
In architecture: ppc
The short answer is that Gatekeeper has changed in the past year. For apps to be approved by Gatekeeper, they now need to be signed in OS X 10.9.5 or later, which contains the latest signature. Due to changes like these, there's little wonder why I have sprouted at least three grey hairs due to dealing with code signing and provisioning profiles.
Apple Says: Important: For your apps to run on updated versions of OS X they must be signed on OS X version 10.9 or later and thus have a version 2 signature. They also must not contain any custom resource rules. You must sign using OS X 10.9 or later. You cannot just take the codesign utility and move it to an older version of OS X. Mac applications signed with version 2 signatures will still work on older versions of OS X.
Gatekeeper changes in OS X 10.9.5 and later
- All packages within the app need to be signed, including Automator plug-ins and actions, frameworks, helper tools, shared libraries, etc.
- Sign with the more modern version of codesign (v2), so when verifying with the command
codesign -dvvv app_name.app
, the second to last line should say "Sealed Resources version=2"
, instead of "version=1"
.
- Resource rules are no longer supported.
What to sign
- Frameworks
- Automator actions
- Plug-ins
- Helper utilities
- The app
How to sign
- Sign from the inside out. Sign the inner components before signing the entire application package.
- Let
codesign
guide you. It will fail if any components still need to be signed.
Start by trying to sign the main application bundle. If any enclosed subcomponents need to be signed, you will be notified.
codesign --force --sign "Developer ID Application: John Doe" MyGreatApp.app/
MyGreatApp.app/: replacing existing signature
MyGreatApp.app/: code object is not signed at all
In subcomponent: /Users/jdoe/Desktop/MyGreatApp.app/Contents/Library/Automator/Foo.action
In this example, the Automator action named Foo still needs to be signed.
codesign --force --sign "Developer ID Application: John Doe" MyGreatApp.app/Contents/Library/Automator/Foo.action
In the UNIX world, no news is good news. If you sign this bundle and nothing else comes back after the process is complete, assume everything is good. This works fine for signing Automator actions. If you are trying to sign a workflow, the process requires a little extra work. If you try and sign the top level of the workflow package, you will receive the following error:
codesign --force --sign "Developer ID Application: John Doe" MyGreatApp.app/Contents/PlugIns/Bar.workflow/
MyGreatApp.app/Contents/PlugIns/Bar.workflow/: code object is not signed at all
In subcomponent: /Users/jdoe/Desktop/MyGreatApp.app/Contents/PlugIns/Bar.workflow/Contents/document.wflow
The correct way to sign a workflow is to first sign the XML file document.wflow, then sign the enclosing workflow file.
codesign --force --sign "Developer ID Application: John Doe" MyGreatApp.app/Contents/PlugIns/Bar.workflow/Contents/document.wflow
codesign --force --sign "Developer ID Application: John Doe" MyGreatApp.app/Contents/PlugIns/Bar.workflow/
Problem Signing an Old Automator Workflow
Here is an error which occurs when trying to codesign the old Automator workflow plug-in which is intended for Leopard systems.
codesign --force -v --sign "Developer ID Application: John Doe" MyGreatApp.app/Contents/PlugIns/Baz.workflow/
MyGreatApp.app/Contents/PlugIns/Baz.workflow/: bundle format unrecognized, invalid, or unsuitable
To work around this issue, an Info.plist file needs to be included into the workflow bundle's Contents folder. An example Info.plist file is below. Replace the CFBundleName's value with the name of the workflow.
Example Info.plist:
<?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>CFBundleName</key>
<string>Baz</string>
</dict>
</plist>
Verify
Once the application and all of its subcomponents have been properly code signed, verify using codesign
and spctl
to ensure that everything is good.
codesign --verify -v MyGreatApp.app
MyGreatApp.app: valid on disk
MyGreatApp.app: satisfies its Designated Requirement
spctl -a -t exec -vv MyGreatApp.app
MyGreatApp.app: accepted
source=Developer ID
origin=Developer ID Application: John Doe
Packaging
When I was initially packaging Permanent Eraser 2.6.3 as a DMG, I used FileStorm 1.9.5. Unfortunately, this did not package the application correctly, so the app could not be verified properly by Gatekeeper. To work around this problem, I used FileStorm 2.0.2. Zipping the application from the Finder also works.
References