Solipsism Gradient

Rainer Brockerhoff’s blog

Browsing Posts tagged Xcode

As you may have seen elsewhere, Apple has just approved publication of RB App Checker Lite 1.1.3 (build 320) on the Mac App Store, and I’ve simultaneously published the Developer ID version (build 321) and updated the product page.

While the main focus of this version is to do some additional checks, fix bugs and display some information that users have requested, the XcodeGhost story broke just after I uploaded the first binary for review, and I had to remove it in order to see what RB App Checker Lite could do to detect this breach of security.

Assuming you’ve read the excellent summaries linked to in the previous paragraph, you may be interested in what I found inside the “ghosted” version of Xcode. Briefly, the hack alters the script Xcode uses to link an app’s binary; it also inserts look-alike versions of the CoreServices framework into the iOS, iPhone Simulator and OS X SDKs inside Xcode.

All this of course breaks Xcode’s code signature and, under normal circumstances, running such a hacked version would — after the customary delay for checking, 2 to 5 minutes — be detected by GateKeeper and it would advise the developer that “‘’ will damage your computer. You should move it to the Trash.” And the previous version of RB App Checker Lite would advise that “…requirements and resources didn’t pass static validation” and point at the changed file.

You’d think that that would take care of the matter, but it turns out that the affected developers turned GateKeeper off entirely, no doubt to get rid of the several minutes delay. After that, versions of their apps uploaded to the App Store would have been linked with a static library containing categories on Cocoa classes such as UIApplication, UIWindow and so forth; this static library having been hidden inside the added frameworks.

Needless to say, the new version of RB App Checker Lite also detects the added frameworks and warns: “3 frameworks are suspect: they use system names but are NOT signed by Apple!”.

This is both good and bad news. The good news is that this specific version of XcodeGhost — or any similar hack that hides code inside bogus frameworks looking like Apple’s frameworks — can be detected. The bad news is that this specific tactic depends on passing a casual visual inspection of the SDKs inside Xcode; in other words, the names and file paths used look reasonable and mostly duplicate Apple’s names and conventions.

This works because Xcode is a huge application; it contains nearly 5 thousand auxiliary executables. The latest Xcode beta has several SDKs for each of the 7 platforms it supports, and each SDK has an included instance of all system frameworks, both public and private, for that particular combination. Unfortunately, not all these frameworks are currently signed by Apple — only 2/3 of them are, and not in a consistent manner. (In all fairness, the percentage has been creeping up a little with each release.)

Therefore, unless you check the entire app contents with GateKeeper, RB App Checker Lite (or even the codesign command-line utility), it will be humanly impossible to pick out visually — by inspection in the Finder — if anything has been changed inside Xcode. So keep GateKeeper turned on! One suggestion Apple should implement is running GateKeeper tests for Apple-signed software even if GateKeeper has been deliberately disabled.

So, what to do about “infected” apps? Unfortunately the news is not good there. (By the way, I’m surprised that no infected apps were — as yet — found on the Mac App Store.) As I said, infected apps contain linked-in categories on Cocoa classes, using plausible English method names. Writing such categories is perfectly legal and even plausible — I’ve done so myself. Having code inside these categories do things that are allowed by the app’s entitlements, such as sending/receiving data over the net, is also perfectly legal and plausible. There seem to be some utilities out already that purport detecting such code, but I suppose they’d turn up a lot of false positives unless they check for these specific combinations of symbols — not very future-proof.

By the same token, Apple can’t really do these tests comprehensively when an app is uploaded to the store. They can and do check for private or “suspect” APIs being called, but as far as I can see the present XcodeGhost doesn’t use anything like that.

Coming back to RB App Checker Lite: it currently does NOT look inside executable code at all. Should it do so? I’m reluctant to implement that; it’s not clear what exactly to look for, regarding hacks like XcodeGhost, and it would mean that checking Xcode and similar huge apps would take tens of minutes or even more. I’m open to suggestions, however… comment here or email me!

Apple’s (pre-)announcement of the Apple Watch left the tech world in the usual disarray. Is it an expensive knock-off of Android watches (people tell me there is such a thing!)? Is it an attack on the high-end Swiss watch market? Is it an attack on the low-end Japanese watch market? Is it an even more transparent lock-in attempt on soi-disant “Apple fanbois”? I’d answer “no” to all those questions, but right now I’m more interested in the hardware and software technology of the watch.

Notice that the above link doesn’t mention iOS anywhere, but this other link has the magic word: WatchKit. Quote: “WatchKit Apps. Soon your favorite apps will feature controls and interactions unique to Apple Watch, enabling you to enjoy them in dynamic new ways.

Speculations about WatchKit since then usually have mentioned one or two assumptions:

  1. WatchKit will be written in/accessible only from Swift;
  2. WatchKit apps will run under iOS on the Apple Watch.

The first is, of course, wishful thinking from developers investing in the new Swift language. The second is, in my opinion, completely unwarranted and I’ll try to explain why.

This post is the most plausible so far: “WatchKit apps will ship as embedded binaries in iPhone apps, using the same basic principals [sic] as iOS 8 extensions. There will be some mechanism for the watch paired to an iPhone to detect and automatically install these ‘apps’ based on what is available on the paired iPhone. Delete the container app from the iPhone, it disappears from the watch. Xcode will have a template to add a WatchKit app to an iPhone app project.

Let’s back off WatchKit for a second and look at what we’ve seen of the hardware. The entire main board is shrunk down to a single unit: the S1. If you stop the middle introduction film at 4:46, you’ll see that it’s really a collection of chips and SMT components on an encapsulated multilayer board — not really a “single chip” as the narration says, but many large CPU “chips” nowadays are like that, too. Other than the S1, there’s of course the “Taptic Engine” assembly which does the wrist tapping, the crown sensor assembly, antennas and display, and the most important part: the battery.

Battery life is the make-or-break feature of the Apple Watch. iFixit’s disassembly of the Moto 360 watch shows why: there’s a square peg battery inside a round casing, rated at 320 mAh. Even though Motorola apparently build their own batteries, they don’t have enough volume to do a round one. Apple doesn’t have a volume problem and their casing is square, so they’re free to use all remaining volume for a longer-lasting battery.

The 320 mAh rating and the typical battery life of 12 hours of the Moto 360 means that the watch consumes, on the average, just under 27 mA. But they run Android on the watch, using an off-the-shelf TI ARM processor with attached RAM, flash memory, and so forth, so that figure is not surprising. In other words, it’s a stripped-down cellphone/MP3 player.

Suppose that Apple did its usual optimization of battery size, usage, etc., in a stripped-down iPod nano. It’s half the size of the nano, which has a 30-hour life, so we can assume half the battery, meaning 15 hours. OK, that would be marginally acceptable, perhaps.

But remember, the Apple Watch needs an iPhone nearby. In fact, many of the published functions, such as Siri, cellphone call response, GPS and so forth certainly use the iPhone’s hardware and software for that. Remember that one of the culprits of excessive battery usage is generic apps and processes running on the device. Remember that Apple, since the first iPod in 2001, has been very aggressive in optimizing their embedded systems. Remember that the first iPods and iPhones didn’t have any generic apps running on them, either. Remember that Apple already has technologies like Clang, OpenCL and Metal…

All that said, why run iOS and generic applications on the Watch at all? So here’s what I think likely about the real implementation.

  • Watch OS (or whatever it’s called — did they explicitly call it anything?) will not be a stripped-down iOS; maybe even not a Darwin derivative. It will be a highly optimized embedded system that has a few apps running in as few processes as possible. It will be very robust because it will be able to do only a fixed set of functions.
  • In other words, it will run only those things that may run while the paired iPhone is not available; we don’t know yet, but that might be just the timekeeping and pulse measuring apps. If the iPhone is there, the Watch will also work as a specialized I/O and display device for the apps installed there.
  • WatchKit will run on the paired iPhone inside a special server process; a matching iOS app will show installed Watch apps — probably those apps will be from the normal App Store, since they usually will have an iOS counterpart.
  • So, an installed Watch app will have at least some sort of preference app or pane on the iPhone; no use typing in passwords and such on the Watch, right? The part written in/for WatchKit will contain a server plugin that does the heavy lifting, data collating and communicating with the outside world, but it will also contain the application logic itself, commanding the Watch to do or display certain things.
  • I don’t mean to imply that the Watch will run a full WebKit client and the iPhone a web server, that might be overkill. Perhaps a useful subset of that, perhaps some variation of Display Postscript, some interpreted command language, or just a sequence of drawing orders? The important part is that there’ll be a single process on the Watch for doing the UI, and all the application-specific parts can be offloaded to the iPhone.

One consequence is that you can forget the idea of “jailbreaking” the Watch to connect to a non-iPhone, of course. Another one is that battery life might be at least a day, maybe even two or more. Nothing on Apple’s site so far contradicts any of my reasoning.

So, will WatchKit be accessible from Swift apps? Certainly. Will it itself be written in Swift? I doubt it for now. Maybe in iOS 9 some of the frameworks in iOS (and OS X) will have been rewritten, assuming that by then the Swift optimizer will be good enough. But that won’t be the case in a few months.

Possible but unlikely: WatchKit may have an API to download actual application code to the S1, which may (or may not) have an ARM-like architecture. Only in such a case — and since there will be no Cocoa/iOS frameworks on the Watch — I would expect the downloaded code to be in Swift (without optionals!), for extra safety; can’t have the Watch crashing and rebooting, right?

Update: Marcel Weiher kindly reminded me of CarPlay, which apparently works like that; nobody would say that cars are running iOS. On the other hand, in that case, the device is connected over USB (that is, reasonable bandwidth) and the car doesn’t have any battery life problems.

Comments welcome.

Over two weeks ago, Apple at WWDC announced something entirely unexpected: thousands of new APIs and a brand-new programming language, Swift. No hardware, of course; it’s a developers conference, remember?

Reactions varied all over the spectrum. Non-developers (especially “industry analysts”) mostly had no idea what it meant: they said Apple had announced “nothing”. Almost all developers, however, were ecstatic — “the most significant event Apple ever staged“. Regarding Swift, this initial enthusiasm diverged as soon as people read the (relatively sparse) documentation and actually began to play around with the language — a very early beta version was available for download soon after the announcement. Hilarity, chaos and pandemonium ensued; tension, apprehension and dissension had begun.

As usual, almost everybody tried to project their grievances, expectations and experiences onto the new language. The open-source advocates griped that no source was available. The cross-platform advocates complained that there was no version running/compiling for Android (as if Apple would have any interest in promoting that!). The Objective-C programmers unsuccessfully tried to translate their code into Swift and complained that there was only limited dynamic dispatching and introspection. The C programmers complained that there were no preprocessor macros and that Swift seemed to be “Objective-C without the C”. The Haskell/Erlang/Scala programmers complained that many functional programming facilities were missing, and that the language was “too mutable”. The Java programmers complained that the language was “too C++-like”, but resented the lack of exceptions. The C++ programmers also resented the lack of exceptions and wanted std::somethings. The Type Theorists complained that generics were “not generic enough”. JavaScript programmers… well, you get the idea. Almost everybody complained about Array mutability semantics, about missing semicolons and the parsing of whitespace, and (of course) said that the syntax “looked weird”. Serious fights erupted on Twitter, disagreeing on whether Swift was a “modern” language and what Apple’s intentions were.

And, as always happens, many people said, in effect, “OMG Apple you’re soo stooopid WTF fix this now!”. This is the usual symptom of looking at the surface and not understanding what might be happening underneath.

Voluminous disclaimer and sidenote with historical digressions:

Many of the complaints in the paragraphs above are condensations of what I understood people to be saying and none are meant to be actual live quotes — which is why I didn’t link to any specific instance. I’m not interested in discussing most of these personally right now, thank you.

I’ve been programming since 1969,  in C since 1984, in Objective-C since 2000. I wrote only one application in C++ back in the Classic days — it was pretty much mandatory in the CodeWarrior/PowerPlant days. I did my CS degree in the early 1970’s, when “modern” language still meant ALGOL 68 – see the mind-boogling official reference (large PDF).

When BYTE Magazine‘s special Smalltalk issue came out in 1981, I was very interested, but couldn’t come to grips with the weird syntax. I bought Adele Goldberg‘s classic books about Smalltalk — the blue book (large PDF), the orange book (large PDF) and the green book (large PDF) — and periodically tried to understand them; very difficult without access to a working compiler! In the late 80’s I put these aside (and, unfortunately, lost them in a move). After Apple acquired NeXT in 1996, I became aware of Objective-C’s roots in Smalltalk, but didn’t give it much thought.

Around 2000, restarting my work as an indie developer, I started programming in Objective-C and Cocoa. As an experienced C programmer I had little difficulty with Objective-C, and quickly got used to the nested [[ ]]s. I never wrote a full Carbon app as such. I also never managed to acquire a working Smalltalk compiler, even after a few became available on the Mac. However, a couple of years ago, I found the Smalltalk books in PDF format (as linked above) and was astounded: the formerly opaque things about methods, messages, dynamic dispatching, objects and so forth — suddenly all was clear and obvious! That’s the advantage of using-while-learning, at least for me.

Unlike many colleagues I never hesitated to go beyond Cocoa, always using CoreFoundation, BSD/Darwin and a variety of interfaces according to necessity, and once manual memory management became ingrained, tossing objects and buffers back and forth between the various APIs. Except for short utilities for my own use, I haven’t adopted ARC yet — I found too many edge cases for my established programming habits.

 So, back to Swift. It really appears to be a very pragmatic language. If you look at the generated library header (in Xcode, command-doubleclick on any Swift type to see it), nearly all operators and types are defined there, in often surprising detail. In other words, few language features are hard-wired into the parser/compiler – the Swift library/runtime and the pre-LLVM optimizer are, instead, responsible for the language and its implementation details, and therefore more easily twiddled if necessary.

This is, of course, very convenient for Apple: a small team could tinker around with all aspects of Swift while leveraging most of the existing LLVM infrastructure and keeping up with the latest changes in iOS and OS X. Indeed, in retrospect, it appears that Swift was even driving many of those changes!

Let’s look at a brief timeline to explain what I mean:

  • 2000-2002: Chris Lattner‘s masters thesis on LLVM;
  • 2005: Lattner hired by Apple; Apple uses LLVM for the OpenGL shading language in Mac OS X 10.5;
  • 2006-2008: Apple introduces experimental llvm-gcc in Xcode 3.1; “blocks” and GCD appear;
  • 2009: Apple introduces Clang as an alternative for gcc; OpenCL and Clang static analyzer appear;
  • 2010: Lattner begins working on Swift; Clang fully supports C++ and llvm-gcc is the default compiler;
  • 2011: gcc/gdb are discarded, Clang/lldb are defaults, ARC introduced in Xcode 4.2;
  • 2012-2013: iOS/OS X are fully built with the new infrastructure, Objective-C literals in Xcode 4.4;
  • 2013: Lattner becomes head of the developer tools department;
  • 2014: Swift comes out in Xcode 6.0.

The LLVM team (Lattner, Evan Cheng who is also at Apple, and Vikram Adve of UIUC) also received the 2012 ACM Software System Award, and of course, LLVM, Clang, LLDB are open-source projects being driven forward by many people who also deserve lots of credit.

Nevertheless, it’s tempting to see all this as Chris Lattner’s plan for world domination… just picture him stroking a white cat and going “mwahaha!” 🙂 [Update: Thanks to @darth for the illustration!]

But really, all this points to progress in Apple’s platforms being driven by a consistent plan to modernize and implement new technologies everywhere; even hardware was affected, as the Apple A6 CPU (and no doubt its successors) were designed in parallel with the corresponding LLVM code generator. Similarly, from 2009 forward, software advances like ARC, blocks, GCD, runtime modernizations etc. are now seen as preparing the ground for Swift at all levels.


A few years ago I posted about Apple’s hardware options being enabled by LLVM, and with the A6 that has indeed begun to happen. Apple’s in position now to design their own CPU and just have to write a new optimizer backend for it — and switch architectures in new hardware without users, or even developers, noticing any significant change.

When I began studying programming languages and compilers, UNCOL was the holy grail of programming:  a universal intermediate language to adapt any high-level language/compiler to any machine architecture. LLVM is the first implementation of that.

What does all this mean for Swift? Contrary to what you may hear from some quarters, it’s not an amateurish, ham-fisted attempt at locking developers in to Apple’s “walled garden”. As Apple has said publicly, it’s a systems programming language that ties in to key Apple technologies. I don’t doubt that it’s already being deployed internally and we can expect to see key low-level frameworks — Security, dyld, IOKit are candidates which come to mind — rewritten in Swift as soon as feasible. In the long run, the kernel itself, Core Foundation and others may follow suit; picture “SwiftKit” unifying much of AppKit and UIKit. Making Swift available to developers at this beta stage is good policy but probably not Apple’s primary focus.

But, you may ask, why not use C++ or the hybrid Objective-C++? Why not use a “modern” cross-platform language? What was wrong with Objective-C anyway?

Well, there’s a reason so many low-level frameworks are written in C++ or pure C: runtime speed. Objective-C’s dynamic dispatching has vastly improved over the years but is still a bottleneck, and in 95% of cases is not really necessary — we rarely use id, and strong typing is encouraged everywhere. As for pure C code, when you look at it, there’s always tons of crufty #defines, tricks to avoid C’s legacy problems, spinlocks and stack arrays and overflow checks and… so it’s no wonder Apple decided to start anew with a new language that avoids all of those problems and still interoperates with Cocoa etc. — all while the infrastructure’s being changed underneath.

So, why not C++? Lattner is a C++ wizard, right? All of Clang/LLVM is coded in C++. So is WebKit, Apple’s other major open-source success. I can’t see that changing, and their effort to fully support all of C++’s experimental future features argues that it won’t change. But C++ doesn’t look like a good match for internal Apple technologies like GCD and ARC, and the C++ Standards Committee is certainly not interested in adopting those. On the other hand, judiciously adopting certain things like generics, operator overloading and optimized dispatching is certainly a good thing. And last but not least, Apple now owns/controls the entire toolchain and the systems programming language!

More later; I’ve started to write an entire application in Swift and after that may feel qualified to comment on language details. For now, I’m quite happy with the prospects.

Well, Xcode 4.1 is out of beta. Please note that the “GM” build previously posted on the developer site was NOT the released version, which is now available for free on the Mac App Store. (Open the “Welcome to Xcode” window, it should say “Version 4.1 (4B110)”.)

I’d promised to several people at WWDC to investigate how Xcode 4.1’s lack of support for IB plugins would work out for RBSplitView, and now I can finally post the results here. Unfortunately the news is not good.

Compiling RBSplitView’s “Sample App” target works well under Xcode 4.1 with just a few changes to modernize build settings sand avoid new warnings. The problem comes when trying to open the .nib file. First, the release notes say you should do this in Terminal:

	defaults write "IBKnownPluginPaths.3.2.7"
		-dict-add "net.brockerhoff.RBSplitView.IBPlugin"

which I did.

Opening the nib file then offers to remove the dependency on the plug-in:

and going ahead lists several warnings and issues.

The way this works is interesting. All RBSplitViews and RBSplitSubviews are converted to NSCustomViews – meaning that they’re stored as plain NSViews in the nib file, -initWithFrame: is called on unarchiving (instead of -initWithCoder:); the view’s class is reset to RBSplitView or RBSplitSubview, as the case may be, and all custom attributes are then set through key-value coding.

I suppose this would work quite well for less complex views, but it didn’t work out of the box for RBSplitView. First of all, this KVC stuff was quite new-fangled when I wrote it, and I didn’t see any need to use it until I had to update the RBSplitView.ibplugin for Xcode 3.1. At the time, I simply wrote some KVC methods for the ibplugin additions, mainly to simplify setting all those attributes from inside Interface Builder… it all worked fine.

Converting the nib file generates a lot of exceptions as the KVC methods just aren’t there in the framework code. I tried a quick fix, copying and pasting them from the plugin code, but that didn’t work out too well: RBSplitView doesn’t like being reincarnated from the nib file piecewise like that, and it seems that the attributes get set too late or in the wrong order.

I suppose some fiddling with the copied methods will fix that, but it’ll be at best a stop-gap measure. The converted nib file no longer adjusts the RBSplitSubviews properly and it’d be too easy to make a big mess of it, should you try to change anything in there. Even so, I’ll try to make some time available to get this working.

Apple says Xcode 3.2.6 is “unsupported” under Lion. If you already have it installed in a separate folder when you upgrade it will mostly continue to work, but I found that running Interface Builder 3 crashes when you have the RBSplitView plugin open. Probably the best bet, for now, is running Snow Leopard Server in a virtual machine and installing Xcode 3.2.6 in there.

Looking back over my WWDC predictions here, I was struck by how boring they were. The same sort of expectations every year, only everything was twice as fast, or large, or whatnot, than the year before. And this year, coming into a conference which is almost completely not about my main platform – the Mac – I noticed I didn’t even have enough information or interest to do the obligatory prediction post.

I was told that over 60% of the developers this year were newbies both to WWDC and to developing for Apple. This seemed, even, a low estimate; I did meet friends from years past, some of them real old-timers, but there weren’t as many as I’d expected – and almost none of the people I didn’t know, that I talked with, were doing anything on the Mac, although some said they’d try to do so sometime in the future.

Indeed, the Mac OS was conspicuous by its almost total absence in the session list, and it was mentioned only offhandedly by Steve Jobs during the keynote – only once, I think. Another, more unexpected, absence from the keynote was the iPad: this, too, was mentioned mainly regarding sales figures, and the rest of the keynote was all about the iPhone 4 and the newly christened iOS 4.

On consideration, however, it makes sense not to talk about the iPad in the keynote: Jobs is notorious for presenting exactly what he wants the press to publish, and distracting them with too many topics is counterproductive. The iPad has had its presentation a few months ago and is selling so well that they’re probably scared that more people will want one; the factories are at max, and cases and other accessories are back-ordered for days or weeks.

Also, an upgrade for the iPad might be a little premature at this point. Any new version would raise protests from those zillions of people that just bought one; the Flash RAM industry is barely keeping up; a faster CPU would need to be dual-core. Regarding the new fancy Retina screen technology, an iPad screen at about 300 dpi would be 2400 by 1800 pixels! I don’t think any mobile video chip can handle that today. iOS 4 is about the only upgrade that’s reasonable to expect to come out quickly.

The iPhone 4 looks good indeed. I don’t need a cellphone myself but the dual cameras and other goodies are tempting; I find myself wishing that Apple would go into digital cameras again. Still, to me, the real star of this WWDC is Xcode 4, the existence of which was also released to the public today; it’s a major step forward, and – as I said several times in the past – many of its features seem to have been enabled by LLVM and its various side projects. One of them, the lldb debugger, is the one I’m particularly interested in; I never liked gdb much.

Many people asked me if I, too, am afraid that Apple will drop the Mac and Mac OS X entirely in the future. Well, I certainly am not! After all, what else would you use to develop for iOS? Xcode 4, for one, seems positively need a 27″ screen for best use – I’m glad I bought a 27″ iMac not too long ago. While the iOS devices might eventually be the tool of choice for consumers to do most of what they on laptops today, laptops will still be useful, and powerful desktops will always be necessary for anything that needs more CPU or graphics power. That said, I can see the laptop line compressing to, say, two models next year, and the Mac Pro going away entirely, or at least replaced by a model seriously more powerful than the high-end iMac.

To close for today, it is safe to say that – without violating any NDA in the process – is that, at least during the next 4 days, whenever any demo hits a glitch, the presenter will ask the audience to turn off its WiFi devices. I saw it happen already, in fact. 🙂

AddLicense tool


So, to start things going again… I was looking at my RSS feeds for the first time in almost 5 months, and read Dan Wood of Karelia fame explaining about Converting Rich Text to TEXT/styl resources for an SLA on a Disk Image.

My own workflow for building a release disk image uses a small tool I’ve written for that. You can download it here. Here’s the help text it prints out if you run it without arguments:

   Add one license at a time to a (unflattened) disk image.
   Usage: AddLicense /path/to/TheUnflattened.dmg Language /path/to/TheLicense.rtf
   Languages supported: da nl ko ja fr it fi pt sv en es de nb
   You can also use long equivalents like English, French etc.
   The first language added will be the default language (usually English).

Here's an actual usage example from a build script:

   hdiutil unflatten "$SOURCE_ROOT/My.dmg"
   "$BUILT_PRODUCTS_DIR/AddLicense" "$SOURCE_ROOT/My.dmg" English "$SOURCE_ROOT/EnglishLicense.rtf"
   "$BUILT_PRODUCTS_DIR/AddLicense" "$SOURCE_ROOT/My.dmg" French "$SOURCE_ROOT/FrenchLicense.rtf"
   hdiutil flatten "$SOURCE_ROOT/My.dmg"

and I use the “flatten” and “unflatten” arguments to hdiutil to massage the disk image.

The trick (as Dan points out in his post update) is that you can use ‘RTF ‘ resources instead of TEXT/styl. I received this interesting tidbit through oral tradition; I’m not a 100% certain, but I think it was through some code that Marko Karppinen showed me a few years ago. Pass it on.

If there’s interest, I may clean up and publish the source sometime, though it uses all sort of gronky old APIs (Resource Manager etc.).

Update: the link above now downloads the complete Xcode project. I also included it on my source code page.

Re: AddLicense tool

No comments

I just published the Xcode project for the AddLicense tool I mentioned previously. Enjoy.

Re: AddLicense tool

No comments

Posted by 0xced:

Rainer Brockerhoff wrote:

If there’s interest, I may clean up and publish the source sometime, though it uses all sort of gronky old APIs (Resource Manager etc.).

Oh yes, there is interest! icon_wink.gif

Photos licensed by Creative Commons license. Unless otherwise noted, content © 2002-2017 by Rainer Brockerhoff. Iravan child theme by Rainer Brockerhoff, based on Arjuna-X, a WordPress Theme by SRS Solutions. jQuery UI based on Aristo.