<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>furbo.org &#187; Development</title>
	<atom:link href="http://furbo.org/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://furbo.org</link>
	<description>by Craig Hockenberry</description>
	<lastBuildDate>Sat, 28 Jan 2012 02:36:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Sandboxing</title>
		<link>http://furbo.org/2012/01/23/sandboxing/</link>
		<comments>http://furbo.org/2012/01/23/sandboxing/#comments</comments>
		<pubDate>Mon, 23 Jan 2012 19:02:43 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Advice]]></category>
		<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=429</guid>
		<description><![CDATA[The recent release of xScope 3.0 is our first product to use the new application sandbox that will soon become a requirement for submission to the Mac App Store. I&#8217;d like to share some experiences and advice on how to use it in your own products.
First off, Ivan Krstić and the rest of the team [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://xscopeapp.com">recent release of xScope 3.0</a> is our first product to use the <a href="http://www.tuaw.com/2011/11/02/apple-to-require-sandboxing-in-mac-app-store-apps-as-of-march-20/">new application sandbox</a> that will soon become a requirement for submission to the Mac App Store. I&#8217;d like to share some experiences and advice on how to use it in your own products.</p>
<p>First off, <a href="https://twitter.com/#!/radian">Ivan Krstić</a> and the rest of the team at Apple have done a great job in making the whole process <a href="http://developer.apple.com/library/mac/#documentation/Security/Conceptual/AppSandboxDesignGuide/AboutAppSandbox/AboutAppSandbox.html">easy to implement</a>. Adding entitlements and signing your code will be the least of your worries as you transition to the new sandbox.</p>
<p>Of course there are some applications that have a harder time than others: primarily if those apps require access to all or part of the filesystem (think about syncing data with <a href="http://panic.com/transmit">Transmit</a>, for example.) Apps that make use of AppleScript for inter-app communication will also have a difficult time: this includes our <a href="http://takefiveapp.com/mac">Take Five</a> app. Apple is actively listening to developers who are encountering these types of issues, so if you haven&#8217;t <a href="https://bugreport.apple.com">filed a Radar yet</a>, quit bitching.</p>
<p>Speaking of Radar, we encountered a fairly nasty problem after launching xScope. Many of our customers are designers and developers who love SSDs. It&#8217;s common to use a symlink in your Home folder to put big datasets like Pictures, Music and Movies on a separate hard drive. When you do this, <a href="http://www.openradar.me/10739052">folder access in the application sandbox container breaks</a>. A small number of users who use symlinks are also getting crashes after launching the app that was downloaded from the Mac App Store:</p>
<blockquote><p>
xpchelper reply message validation: sandbox creation failed: 1002<br />
Container object initialization failed: The file couldn’t be opened.
</p></blockquote>
<p>We also encountered a problem when using <a href="http://sparkle.andymatuschak.org/">Sparkle</a> to update an app running in a sandbox: <a href="https://twitter.com/#!/radian/status/147795529974300672">an app can&#8217;t update its own binary</a>. Changing Sparkle so that it uses an XPC service is a major architectural change, so we decided to remove the sandbox for the version we distribute on the website.</p>
<p>Besides being the path of least resistance, it also gives us a version of xScope that doesn&#8217;t run into the sandbox bugs reported above. I highly recommend that you give yourself this option for any customers that experience sandbox related problems.</p>
<p>All things considered, adding an application sandbox has been a fairly smooth transition. But it&#8217;s also clear that we&#8217;ve only just begun putting the genie back in the bottle.</p>
<p><strong>Updated January 27th, 2012:</strong> The bug reported above is a duplicate of <a href="rdar://problem/9865143">Radar 9865143</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2012/01/23/sandboxing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Homebase</title>
		<link>http://furbo.org/2012/01/16/homebase/</link>
		<comments>http://furbo.org/2012/01/16/homebase/#comments</comments>
		<pubDate>Mon, 16 Jan 2012 22:17:56 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Observation]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=409</guid>
		<description><![CDATA[A lot of people I know and respect have been commenting on problems associated with the iPhone mute switch:
John Gruber – On the Behavior of the iPhone Mute Switch
Andy Ihnatko – Unmuting on The Mute Question
Marco Arment – Designing “Mute”
Guy English &#8211; Mute This
Both sides of the argument have valid points-of-view. This really is a [...]]]></description>
			<content:encoded><![CDATA[<p>A lot of people I know and respect have been commenting on problems associated with the iPhone mute switch:</p>
<p><a href="http://daringfireball.net/2012/01/iphone_mute_switch_design">John Gruber – On the Behavior of the iPhone Mute Switch</a><br />
<a href="http://ihnatko.com/2012/01/15/unmuting-on-the-mute-question/">Andy Ihnatko – Unmuting on The Mute Question</a><br />
<a href="http://www.marco.org/2012/01/14/mute">Marco Arment – Designing “Mute”</a><br />
<a href="http://kickingbear.com/blog/archives/282">Guy English &#8211; Mute This</a></p>
<p>Both sides of the argument have valid points-of-view. This really is a situation with no right answer given the current mechanisms.</p>
<p>That got me thinking that there might be something missing that&#8217;s causing this ambiguity. I&#8217;ve come to the realization that this is a problem bigger than just alarms going off at inopportune moments. What we really want is for the devices in our pocket to behave differently depending on where they&#8217;re physically located.</p>
<p>Let&#8217;s imagine a new feature in iOS called &#8220;Homebase&#8221;. A user would be presented with a simple UI that lets them select a location that&#8217;s a &#8220;safe&#8221; environment. After the setup is complete, your Homebase would be recognized by GPS coordinates and/or available Wi-Fi networks. The important thing here is that the user gets to define where they feel safe with their device.</p>
<p>With that information developers can make smarter decisions:</p>
<ul>
<li>
Alarms that go off while the mute switch is on make noise at Homebase and just vibrate elsewhere. There&#8217;s no need to worry about alarms going off in public places (such as concert halls) and you won&#8217;t oversleep when you go to bed with a mute switch on.
</li>
<li>
The lock screen doesn&#8217;t need to display a Passcode lock at Homebase. People who use the Remote app with their Apple TV will no longer be annoyed by an unnecessary security precaution, nor will folks forget to turn their Passcode lock back on when they leave for the local bar (where they&#8217;re certain to get a <a href="https://twitter.com/#!/chockenberry/statuses/125410955369783296">Poopin&#8217;</a> tweet.)
</li>
<li>
Apps, like Find My Friends, could use cached Apple ID credentials at Homebase and avoid asking the user for them over and over and over and over again.
</li>
</ul>
<p>Of course, this feature is needed most by people who don&#8217;t even know the Settings app exists. It&#8217;s my opinion that if developers are careful with this additional knowledge about the user and device, default behavior can be adjusted appropriately without additional confusion. It&#8217;s analogous to the Energy Saver on the Mac: people don&#8217;t question why the screen dims when the power cord is removed because it just &#8220;makes sense&#8221;.</p>
<p>The examples above use Apple&#8217;s own apps, but the Homebase status would be useful for third-party developers, too.</p>
<p>If you&#8217;d like to see something like Homebase in iOS, please be sure to file a <a href="http://www.openradar.me/10702394">duplicate Radar</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2012/01/16/homebase/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Un-Trusteer-ed</title>
		<link>http://furbo.org/2011/08/01/un-trusteer-ed/</link>
		<comments>http://furbo.org/2011/08/01/un-trusteer-ed/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 16:16:17 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Advice]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Observation]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=395</guid>
		<description><![CDATA[The bank we use for our business account recently mandated the use of a product called Trusteer Rapport while accessing our information online. Although Mac OS X doesn&#8217;t have any problems with &#8220;increasingly sophisticated malware in the online environment&#8221;, I do need to periodically check our accounts and transactions so I proceeded with the installation.
The [...]]]></description>
			<content:encoded><![CDATA[<p>The bank we use for our business account recently <a href="https://www.suntrust.com/Microsites/ocm_rapport/index.htm">mandated</a> the use of a product called Trusteer Rapport while accessing our information online. Although Mac OS X doesn&#8217;t have any problems with &#8220;increasingly sophisticated malware in the online environment&#8221;, I do need to periodically check our accounts and transactions so I proceeded with the installation.</p>
<p>The first warning sign was after starting the Installer: I was prompted for an administrator password indicating that this software wanted to run from protected areas of my system. Being a developer, I immediately dug into the installer scripts and configuration files to see that the app is placing items in the Rapport/bin, PreferencePanes, LaunchDaemons and LaunchAgents folders of the main system Library folder. The launch folders indicate that the software will be run whenever my Mac is restarted and will be able to do things a normal user would not (because of elevated permissions.)</p>
<p>I placed my security concerns aside as I need to access my bank website, so I went ahead with the installation. Afterwards, I was directed to a web page describing the <a href="http://activation.trusteer.com/v3/installation-complete-osx">new software</a>.</p>
<p>Again, as a developer, my first thoughts were suspicious ones. From experience, I know that it&#8217;s not easy to modify Safari&#8217;s user interface in the way that Trusteer was doing. My guess that there would be a new, always active, background process was confirmed by the presence of &#8220;rooksd&#8221; in my process list.</p>
<p>However what happened next really opened my eyes. Safari <a href="http://files.iconfactory.net/craig/bugs/Rapport.txt">crashed</a>.</p>
<p>Of course that, in and of itself, isn&#8217;t the end of the world. But I was surprised to see a new library named RapportUtil1 while looking at the Safari crash report. It was pretty clear that the new Trusteer software caused the crash. But how?</p>
<p>As a longtime Objective-C developer, I know a thing or two about <a href="http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html">&#8220;method swizzling</a>&#8220;. In a nutshell, this allows a developer to replace the functionality of code they don&#8217;t have direct access to (typically in the system or other frameworks.) </p>
<p>Seeing &#8220;_nsapplication_sendEvent_override&#8221; tells me that Trusteer is using this technique to change the behavior of Safari. The function that is being affected is <a href="http://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/Reference/Reference.html#//apple_ref/occ/instm/NSApplication/sendEvent:">-sendEvent:</a> &#8212; the part of every Cocoa application where mouse, keyboard and other input is routed.</p>
<p>Method swizzling is a dangerous activity. You have to make assumptions about how some other code, that you&#8217;ve never seen, is behaving. You also need to think about how that code might change in future versions. There are extreme cases where this technique can be effective: overriding the default behavior of my web browser is not one of them.</p>
<p>It&#8217;s clear that the folks taking control of my browser aren&#8217;t as clever as they think. Do you see a common theme when you search Apple&#8217;s discussion forums for &#8220;<a href="https://discussions.apple.com/search.jspa?peopleEnabled=true&#038;userID=&#038;containerType=&#038;container=&#038;spotlight=true&#038;q=RapportUtil1">RapportUtil1</a>&#8220;?</p>
<p>Even more troubling is the method being overridden: every key press or mouse movement is first being sent to Rapport and then forwarded onto Safari. Since this happens often, the intruding software can do pretty much whatever it wants, whenever it wants. And remember that part of this package is running with elevated permissions in the background.</p>
<p>After <a href="http://twitter.com/#!/chockenberry/status/97361639430553601">mentioning</a> my findings on Twitter, I got back some very interesting replies. Graham Lee (<a href="http://twitter.com/iamleeg">@iamleeg</a>) pointed out that I&#8217;m not the first developer to <a href="http://broadcast.oreilly.com/2008/12/snake-oil-legitimate-vendors-s.html">question the technical merits</a> of this software. But then Peter Hosey (<a href="http://twitter.com/boredzo">@boredzo</a>) dropped the real bomb. Trusteer tacitly admits to <a href="http://www.trusteer.com/company/press/trusteer-finds-two-thirds-internet-users-reuse-their-online-banking-credentials-other-">recording my password</a>. That&#8217;s easy to do when you take control of -sendEvent:.</p>
<p>Essentially, my bank is asking me to install is a <a href="http://en.wikipedia.org/wiki/Keystroke_logging">keylogger</a>. Just so they can warn me not to use the same password on suntrust.com and playboy.com.</p>
<p>Hopefully, the engineers behind Rapport are smart enough to be using <a href="http://en.wikipedia.org/wiki/Password#Form_of_stored_passwords">hashed passwords</a> rather than clear text. And hopefully none of the personal information Safari has access to is being forwarded to the Trusteer servers. And hopefully they&#8217;re not recording how many times I visited playboy.com last month. But that&#8217;s beside the point, because as a closed source product, no one can audit their activity. That&#8217;s not true with <a href="http://www.webkit.org/">Safari</a>. </p>
<p>Oh, and there&#8217;s one other thing: the Rapport software isn&#8217;t supported on Lion. One of the tenets of method swizzling is to test your software early and often with any new release of the system or framework that it&#8217;s modifying. As a developer, you need to be proactive about fixing any problems that pop up in the code you are overriding. Not doing so is irresponsible and puts your users at risk. The last update for Rapport was in 2009.</p>
<p>(One could speculate that the new <a href="http://arstechnica.com/apple/reviews/2011/07/mac-os-x-10-7.ars/9#privilege-separation">privilege separation architecture for Safari</a> in Lion is causing Trusteer&#8217;s developers a lot of headaches. The other tenet of method swizzling is to remember that it&#8217;s not a matter of <strong>if</strong> your hack will break in the future, but rather <strong>when</strong> it will break and how painful it will be to fix.)</p>
<p>Needless to say, I have uninstalled this software and will never be installing it again. I would recommend this course of action to any end user.</p>
<p>But that leaves me with a problem: how do I access my bank&#8217;s website? I have three options:</p>
<p>1) Find another bank. This is a difficult choice, as there are many systems that are hooked up to this account: ACH transactions for sales via iTunes, bi-weekly payroll, automatic payments for services, etc. I&#8217;d also like to give SunTrust a chance to reconsider their position in requiring this software (they will be getting a copy of this report.)</p>
<p>2) Use the telephone. I can call the bank when I need the information. Sure they&#8217;ll get tired of hearing from me, and it will cost them more for customer service, but it&#8217;s their choice to require Trusteer Rapport.</p>
<p>3) Run the Trusteer Rapport software in locked down environment. Once it&#8217;s supported on Lion, it should be possible to create a virtual machine that that will only be used to access the bank website. Needless to say this is inconvenient, a waste of resources, and severely limits my ability take advantage of my bank&#8217;s services.</p>
<p>In closing, I&#8217;ll leave you with one final irony: I will <strong>never</strong> be able to access my bank&#8217;s website from what is arguably the most secure computing device in existence today. That&#8217;s because the iPad is not a <a href="http://www.trusteer.com/supported-platforms">supported platform</a>. Apple only allows third-party applications to run in a secure sandbox where they can&#8217;t affect other applications or the operating system. What you&#8217;ve seen above is exactly the reason they&#8217;ve done this.</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2011/08/01/un-trusteer-ed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Rise and Fall of the Independent Developer</title>
		<link>http://furbo.org/2011/07/13/the-rise-and-fall-of-the-independent-developer/</link>
		<comments>http://furbo.org/2011/07/13/the-rise-and-fall-of-the-independent-developer/#comments</comments>
		<pubDate>Wed, 13 Jul 2011 18:48:59 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Opinion]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=388</guid>
		<description><![CDATA[I&#8217;m old enough to remember a time before the Internet. I know what it&#8217;s like to develop software both with and without a worldwide network.
Little has changed with the process of software development since the 1980&#8217;s. Of course there have been improvements in our tools and techniques, but the basic act of creating software products [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m old enough to remember a time before the Internet. I know what it&#8217;s like to develop software both with and without a worldwide network.</p>
<p>Little has changed with the process of software development since the 1980&#8217;s. Of course there have been improvements in our tools and techniques, but the basic act of creating software products is much the same. What has changed dramatically in the past 30 years is how we distribute our creations.</p>
<p>In the days where software was distributed on magnetic media, such as reels of tape, cassettes, or floppy disks, it cost <strong>a lot</strong> of money to get the product to a customer. As a result, large companies and software publishers were the only ones with the financial resources to get these applications into a retail channel. There were very few independent software developers; and those who did exist were very small operations.</p>
<p>Then along came the Internet and everything changed. Distribution was suddenly cheap.</p>
<p>I remember a conversation with my good friend <a href="http://panic.com">Cabel Sasser</a> a few years ago. He and I were reminiscing about our first foray into online distribution and were surprised that we had the same initial reaction: &#8220;Holy crap! We can put our software on the Internet and people will actually buy it!&#8221;</p>
<p>Many other developers had this same experience and began leaving large companies to work on their own. Making a good living while having the freedom to work on their passion was a <a href="http://daringfireball.net/2005/10/the_life">great life</a>.</p>
<p>Now distribution is going mainstream with the App Store. And it&#8217;s already begun changing the lives and businesses of independent software developers. On the surface, it all looks good. There are more customers, increased revenues, and many great new products.</p>
<p>But this expanded distribution is also putting our business at risk: there are people in this new market who claim a right to a part of our hard work. Either by <a href="http://www.rfcexpress.com/lawsuits/patent-lawsuits/texas-eastern-district-court/76009/lodsys-llc-v-combay-inc/summary/">patent</a> or <a href="http://www.rfcexpress.com/lawsuits/copyright-lawsuits/new-york-southern-district-court/69655/kevin-harper-v-iconfactory-inc/summary/">copyright</a> infringement, developers are finding this new cost of litigation to be onerous.</p>
<p>The scary part is that these infringements can happen with any part of our products or websites: things that you&#8217;d <a href="http://forums.toucharcade.com/showthread.php?t=100387">never</a> <a href="http://www.widgetpress.com/defense">imagine</a> being a violation of someone else&#8217;s intellectual property. It feels like coding in a mine field.</p>
<p>From our experience, it&#8217;s entirely possible that <strong>all</strong> the revenue for a product can be eaten up by legal fees. After years of pouring your heart and soul into that product, it&#8217;s devastating. It makes you question why the hell you&#8217;re in the business: when you can&#8217;t pay salaries from product sales, there&#8217;s no point in building it in the first place.</p>
<p>So, just as in the days of magnetic media, the independent developer now finds him or herself at a point where it is again becoming very expensive to distribute their products to a mass market. This time the retail channel itself is very cheap, but the ancillary costs, both financially and emotionally, are <strong>very</strong> high.</p>
<p>And, of course, only large companies and publishers can bear these costs. My fear is that It&#8217;s only a matter of time before developers find the risks and expenses prohibitive and retreat to the safety of a larger organization. We&#8217;ll be going back to square one.</p>
<p>Over the years many of the top selling apps have been created by independent developers, starting with <a href="http://articles.cnn.com/2008-11-18/tech/iphone.game.developer_1_trism-iphone-app-store">Steve Demeter and Trism</a> at the App Store launch, and continuing to this day with titles like <a href="http://en.wikipedia.org/wiki/Tiny_wings">Tiny Wings by Andreas Illiger</a>.</p>
<p>Losing that kind of talent and innovation to a legal system is the real crime.</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2011/07/13/the-rise-and-fall-of-the-independent-developer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Predators</title>
		<link>http://furbo.org/2011/05/23/predators/</link>
		<comments>http://furbo.org/2011/05/23/predators/#comments</comments>
		<pubDate>Mon, 23 May 2011 17:00:52 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Miscellaneous]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=382</guid>
		<description><![CDATA[Dear Steve,
I&#8217;m one of the developers that is affected by the Lodsys patent infringement claim. I&#8217;m writing not to beg for your support, but rather to give you a better idea of how this legal action affects the average iOS developer.
We&#8217;re a small company. We have 12 employees that have created 14 products for Mac [...]]]></description>
			<content:encoded><![CDATA[<p>Dear Steve,</p>
<p>I&#8217;m one of the developers that is affected by the Lodsys patent infringement claim. I&#8217;m writing not to beg for your support, but rather to give you a better idea of how this legal action affects the average iOS developer.</p>
<p>We&#8217;re a small company. We have <a href="http://iconfactory.com/home/staff">12 employees</a> that have created <a href="http://iconfactoryapps.com/">14 products</a> for Mac and iOS. We have been incorporated in the state of North Carolina since 1999. We won an Apple Design Award in 2008.</p>
<p>We&#8217;ve been doing product development long enough to know that legal expenses are just a part of doing business. But as we both know, the costs of patent litigation can be staggering. As a small company, we don&#8217;t have the resources to defend ourselves, so that leaves us with one option: to pay a licensing fee.</p>
<p>And that worries us and every other iOS developer we know.</p>
<p>In and of itself, paying half of a percent of our App Store sales to Lodsys isn&#8217;t going to put us out of business. The fear we have is that this is the first step on a very slippery slope.</p>
<p>It&#8217;s well known that the top titles in the App Store can earn tens of thousands of dollars per day. There are many predators with dubious patents who see dollar signs when they look at the flock of iOS developers.</p>
<p>What these predators don&#8217;t realize is that for every developer who&#8217;s earning millions, there are many thousands who are earning much less. This backbone of the iOS ecosystem is doing well with work we love, but that is very much at risk with increased legal costs. We wonder what happens when these predators discover that the earnings from these apps are much lower than they expect. Will the licensing fees increase as a result? Will our next infringement be 5%, 10%, or more?</p>
<p>Of course, this is also a slippery slope for Apple. Taking on a legal burden for an entire platform is not something we would want to do, especially when the root of the problem is a screwed up patent system.</p>
<p>We love developing products for iOS and the Mac, but this legal mess has already started killing that enthusiasm. Apple has revolutionized the distribution of software via the App Store and that has been a great boon for smaller developers. It makes us furious that these greedy predators can put all of that at risk with patents.</p>
<p>Thanks for your time,</p>
<p>Craig Hockenberry</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2011/05/23/predators/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A disappointment&#8230;</title>
		<link>http://furbo.org/2011/04/19/a-disappointment/</link>
		<comments>http://furbo.org/2011/04/19/a-disappointment/#comments</comments>
		<pubDate>Tue, 19 Apr 2011 21:26:54 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=369</guid>
		<description><![CDATA[When we released Chameleon at the end of last month, we thought we&#8217;d try something new to raise funds for the project. Selling T-shirts and stock icons seemed like a pretty good way. Boy, were we wrong.
Since March 22nd, we&#8217;ve sold 17 shirts. If you do the math, that will pay for less than a [...]]]></description>
			<content:encoded><![CDATA[<p>When we released <a href="http://chameleonproject.org">Chameleon</a> at the end of last month, we thought we&#8217;d try something new to raise funds for the project. Selling T-shirts and <a href="http://stockicons.com">stock icons</a> seemed like a pretty good way. Boy, were we wrong.</p>
<p>Since March 22nd, we&#8217;ve sold 17 shirts. If you do the math, that will pay for less than a week of our time. And considering that we&#8217;ve already spent more than a week getting things rolling on <a href="https://github.com/BigZaphod/Chameleon">Github</a> and preparing <a href="http://chameleonproject.org/#talk">a talk at the VTM conference</a>, we&#8217;re already running at a deficit.</p>
<p>In summary, we&#8217;re very disappointed with how things have turned out. Not because of the funding, but because there&#8217;s some potential here that will never be realized. We&#8217;ll continue to add things we need for our own products, but don&#8217;t expect to see any documentation or bug fixes that don&#8217;t affect our own code. Any changes or fixes will get pushed out to the community on a schedule that suits us best: probably at the end of minor release cycles (every few months.)</p>
<p>To those of you who were so generous to contribute to the project, we appreciate your support. Unfortunately, we&#8217;re sorry to say that such a low volume of T-shirts doesn&#8217;t warrant the time and energy needed to get them printed up. We&#8217;ll make sure that the credit card orders are cancelled.</p>
<p>Damn.</p>
<p><strong>Updated April 19th, 2011:</strong> To be clear, we&#8217;re not disappointed with the Mac and iOS developer communities. The source of our disappointment is that we can&#8217;t afford to spend time working on general improvements to the framework.</p>
<p><strong>Updated April 20th, 2011:</strong> We&#8217;re hearing a lot of &#8220;let the community help&#8221;—which is great and has already started happening. We will continue to support this aspect of Chameleon: we&#8217;re not giving up on the project.</p>
<p>But the area where the community is not equipped to help is with documentation. We have nine months of experience with porting an iOS app to the Mac: no one else is presently in a position to help other developers achieve the same goal. We also know that writing is a long and difficult task (<a href="http://appdevmanual.com">my book</a> took seven months of full-time work.) A lot of time is going to be wasted without this transfer of information: so be it.</p>
<p>So much of the open source community focuses on the details (code) without looking at the big picture (how people are going to use that code.) And if you try to think beyond the <a href="https://twitter.com/thijs/status/60605470108418048">status quo</a>, you get <a href="https://twitter.com/nzkoz/status/60613528188493824">called names</a>.</p>
<p>We&#8217;re also painfully aware that we&#8217;re new to managing open source projects. It&#8217;s likely that 13 years of <a href="http://iconfactoryapps.com">selling software</a> is tainting our decisions, but our hearts are in the right place: we want to help the iOS and Mac developer communities.</p>
<p>Finally, we&#8217;ve added a more traditional <a href="http://chameleonproject.org/#donate">Donate</a> button on the Chameleon Project page. Thanks in advance for any contribution you can make.</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2011/04/19/a-disappointment/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Revealing</title>
		<link>http://furbo.org/2011/03/22/revealing/</link>
		<comments>http://furbo.org/2011/03/22/revealing/#comments</comments>
		<pubDate>Tue, 22 Mar 2011 17:33:16 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=353</guid>
		<description><![CDATA[To date, the Iconfactory&#8217;s contributions to open source have been fairly small. That just changed: in a big way.
I&#8217;ll be honest here—we&#8217;re a bit nervous about this release. We&#8217;re not used to revealing our work before we&#8217;re completely happy with the results. We&#8217;ve spent over nine months getting this far, but there&#8217;s so much more [...]]]></description>
			<content:encoded><![CDATA[<p>To date, the Iconfactory&#8217;s contributions to open source have <a href="http://sourceforge.net/projects/agkit/">been</a> <a href="http://www.nuclearelephant.com/index.php">fairly</a> <a href="https://github.com/mattgemmell/MGTwitterEngine">small</a>. That just changed: in <a href="http://chameleonproject.org">a big way</a>.</p>
<p>I&#8217;ll be honest here—we&#8217;re a bit nervous about this release. We&#8217;re not used to revealing our work before we&#8217;re completely happy with the results. We&#8217;ve spent over nine months getting this far, but there&#8217;s so much more to do. We&#8217;d like to continue work on this project and get the developer community involved. And that&#8217;s going to take time and money.</p>
<p>So please take a moment to check out the <a href="http://chameleonproject.org">Chameleon Project</a> website and buy an <a href="https://store.iconfactory.com/#chameleon">exorbitantly priced T-shirt</a> to help us achieve our goal. Thanks!</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2011/03/22/revealing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Great writing, terrible reading</title>
		<link>http://furbo.org/2011/03/17/great-writing-terrible-reading/</link>
		<comments>http://furbo.org/2011/03/17/great-writing-terrible-reading/#comments</comments>
		<pubDate>Thu, 17 Mar 2011 19:15:56 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Observation]]></category>
		<category><![CDATA[Opinion]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=334</guid>
		<description><![CDATA[Apple has recently released Xcode 4—a major part of this release is an overhaul of the user interface. Change in your development environment is always a bit disruptive, but overall I think the move towards a single-window environment that adapts to different working modes is a good thing.
But this post is not to debate these [...]]]></description>
			<content:encoded><![CDATA[<p>Apple has recently released Xcode 4—a major part of this release is an overhaul of the user interface. Change in your development environment is always a bit disruptive, but overall I think the move towards a single-window environment that adapts to different working modes is a good thing.</p>
<p>But this post is not to debate these changes to the programming environment. Rather, I&#8217;d like to discuss the new documentation viewer and how it has become unsuitable for both Mac and iOS development.</p>
<p>Apple&#8217;s technical documentation has always been top-notch: well written with just the right amount of technical detail. Unfortunately, the documentation viewer that we use to read this valuable information has been declining in ease of use over the past few releases.</p>
<p>It has gotten to the point where frustration with usability overshadows the excellent content. The best way to describe these annoyances is by example: I often get the feeling that the writers who create this prose don&#8217;t understand how we use it. Hopefully, this critique will help Apple create a viewer that&#8217;s just as good as the information it holds.</p>
<h3>A corrupt index</h3>
<p>A developer coming from Xcode 3 will have a terrible first experience with the new documentation viewer. Any previously installed documentation sets are incompatible with Xcode 4. Methods that you know exist just don&#8217;t show up:</p>
<p><img src="http://furbo.org/wp-content/uploads/2011/03/Search_in_vain.png" alt="Search in vain" title="Search in vain" width="286" height="348" class="aligncenter size-full wp-image-336" /></p>
<p>There are also problems with the Jump Bar navigation stack not being recorded correctly and the browsing history being unavailable (the back button isn&#8217;t available when it should be.)</p>
<p>Presumably, there is a corrupt or incompatible index. The workaround is to delete and re-install the documentation set, but this is far from obvious.</p>
<p>Since I currently have three different versions of Xcode installed (and will continue to use Xcode 3 for the foreseeable future), I&#8217;m wondering if this corrupted/incompatible index will continue to be a problem. Fingers are crossed, but at least now we know what to fix if it breaks.</p>
<h3>Popup hell</h3>
<p>When you hold down the option key and click on a symbol in Xcode, you see the following window:</p>
<p><img src="http://furbo.org/wp-content/uploads/2011/03/Popup_hell.png" alt="Popup hell" title="Popup hell" width="421" height="312" class="aligncenter size-full wp-image-338" /></p>
<p>For novices, this window has some utility—it provides a simple way for them to dig into what is probably unfamiliar territory (&#8221;What&#8217;s a UIWindow anyway?&#8221;).</p>
<p>The problem is that this window becomes a roadblock for experienced developers. We know damn well what a UIWindow is: we need to dig into the details of this important class. Maybe we want to know more about the rootViewController instance or look at some of the methods in UIResponder (because we know it inherits from that.) This helpful popup quickly becomes a hindrance.</p>
<p>In previous versions of Xcode, holding down the shift key along with the option key gave you a quick way to avoid this popup help. In Xcode 4, that shortcut is gone.</p>
<p>Considering that this feature can get in the way hundreds of times per day, this is truly popup hell.</p>
<p><a href="http://www.openradar.me/9149588">rdar://9149588</a></p>
<h3>No methods</h3>
<p>Once you get the documentation index in working order and actually make it past the popup help, your next hurdle is to locate the information you seek. Let&#8217;s say we&#8217;re looking for some background on what happens when a new -rootViewController instance is assigned. We&#8217;ve got the page of documentation, but there aren&#8217;t any controls to show the methods for the UIWindow class:</p>
<p><a href="http://furbo.org/wp-content/uploads/2011/03/No_methods_1.png"><img src="http://furbo.org/wp-content/uploads/2011/03/No_methods_1-300x63.png" alt="No methods" title="No methods" width="300" height="63" class="aligncenter size-medium wp-image-340" /></a></p>
<p>Besides being a pain in the butt, this is wholly inconsistent with the behavior in the code editor:</p>
<p><a href="http://furbo.org/wp-content/uploads/2011/03/No_methods_2.png"><img src="http://furbo.org/wp-content/uploads/2011/03/No_methods_2-300x104.png" alt="Methods" title="Methods" width="300" height="104" class="aligncenter size-medium wp-image-341" /></a></p>
<p>(Note that typing &#8220;ro&#8221; is enough to select &#8220;rootViewController&#8221; in the code editor&#8217;s popup menu. That, followed by the enter key gets you to the code of interest.)</p>
<p>From a developer&#8217;s point-of-view, the header files and the documentation page go hand-in-hand. Make the UI affordances the same and we don&#8217;t have to think about whether we&#8217;re looking at code or the words that describe it.</p>
<p>With a little more digging, you&#8217;ll find that you can get to the rootViewController documentation with the Jump Bar. Unfortunately, it takes a lot more effort than in the code editor: you have to click on the class name, and then move the mouse until the subcategories appear. Choose &#8220;Instance Methods&#8221; and wonder why rootViewController isn&#8217;t there. Then move the mouse back and try Properties.</p>
<p>Bingo (but you don&#8217;t feel like a winner.) And forget about navigating these lists quickly and easily with the keyboard as you can with the code editor.</p>
<p><a href="http://www.openradar.me/9149638">rdar://9149638</a></p>
<h3>Unmanaged complexity</h3>
<p>Our final navigation problem is reading chapter-based documentation. These are the crown jewels of Apple&#8217;s developer documentation. Titles like The Objective-C Programming Language, iPhone Human Interface Guidelines, and the Cocoa Fundamentals Guide are essential reading for all developers, both beginner and advanced. As I began learning about Xcode 4, of course I turned to the excellent User Guide.</p>
<p>These guides typically span many chapters when sections that cover a wide range of topics. And this is how you navigate through those chapters:</p>
<p><a href="http://furbo.org/wp-content/uploads/2011/03/Unmanaged_complexity.png"><img src="http://furbo.org/wp-content/uploads/2011/03/Unmanaged_complexity-300x124.png" alt="Unmanaged complexity" title="Unmanaged complexity" width="300" height="124" class="aligncenter size-medium wp-image-344" /></a></p>
<p>Managing complexity, indeed.</p>
<p>The pity here is that someone in developer documentation has forgotten that a Table of Contents tells a much more important story than the individual chapters. A roadmap lets you visit the destinations efficiently.</p>
<p>To get an idea of how painful this is, try finding the recommended Singleton implementation in the Cocoa Fundamentals Guide using the Jump Bar. I&#8217;ll wait. (For extra credit, count how many menus you open in the process.)</p>
<p>Of course the documentation viewer has a search function, but even that&#8217;s a bit laborious because you have to click on a lot of disclosure triangles to find the right item in the results. Why aren&#8217;t the relevant results opened automatically? (And, yes, option clicking the disclosure triangle can be used to achieve this goal, but the question still remains: why isn&#8217;t this the default action?)</p>
<p><strong>Updated March 29th, 2011:</strong> Matt Neuburg has discovered that for some documents, search results don&#8217;t show where your term occurs; <a href="http://lists.apple.com/archives/xcode-users/2011/Mar/msg00658.html">you&#8217;re shown a higher-level page, but not the actual page</a>.</p>
<p>The root of the problem here and with the method names in the class documentation, is that a deep hierarchy is too hard to navigate. Present the information in a single list and it becomes much more useful. Imagine how bad the code editor navigation would be if it presented a hierarchy based upon classes, properties and methods. It&#8217;s flattened into a single menu for a reason: and those same reasons exist in the documentation viewer.</p>
<p>The Jump Bar is a great addition to Xcode, but it&#8217;s true power lies in having a predictable end point. With code, that end point is a function, property or method. With documentation, that end point is elusive: it varies depending both with the type and the structure of the documentation you&#8217;re viewing. And that&#8217;s a real problem when you&#8217;re looking for something.</p>
<p><a href="http://www.openradar.me/9149683">rdar://9149683</a></p>
<h3>ePub, not PDF</h3>
<p>While we&#8217;re on the subject of this long-form documentation, why isn&#8217;t more of it available in the ePub format used by iBooks? It&#8217;s pretty safe to assume a huge majority of Mac and iOS developers have an iPad and like to use it for technical documentation. Searching for &#8220;Apple Developer Publications&#8221; in iBooks results in only six books. That&#8217;s a great start, but there is still a lot of documentation available only in PDF.</p>
<p>PDF is, of course, an option for iBooks. But turns out to be unsuitable because there is no back button. If you click a link in the PDF file, it&#8217;s a one way proposition. And for technical documentation, that&#8217;s a deal killer.</p>
<p>ePub also has the advantage of better font control and image viewing.</p>
<p><a href="http://www.openradar.me/9149845">rdar://9149845</a></p>
<h3>Some good news</h3>
<p>Fortunately, it&#8217;s not all bad news. This new version of the documentation viewer seems to keep track of its place on the page much more reliably than in the past. Gone are the days where hitting the back button put you back as the top of the page (instead of the method or property you were looking at previously.)</p>
<p>This one simple fix will save developers a huge amount of time. Thanks!</p>
<h3>Ingredients</h3>
<p>This situation with the Xcode document viewer has gotten so bad two developers, <a href="http://twitter.com/alextgordon">Alex Gordon</a> and <a href="http://twitter.com/jeannicolas">Jean-Nicolas Jolivet</a>, have taken matters into their own hands. This ultimate workaround is an application called <a href="http://fileability.net/ingredients/">Ingredients</a>.</p>
<p>Ingredients parses the HTML files used by Apple&#8217;s own viewer and persists the information with Core Data. The result is quick access to the documentation you need with advanced options to filter and sort to your liking. Recent work by <a href="http://twitter.com/tgaul">Troy Gaul</a> added an item to the Services menu so a keyboard shortcut can be created to view the selected symbol from any text editor (include Xcode.)</p>
<p>If the problems mentioned above affect you adversely, take a look at this alternative documentation viewer. And please take a moment and file duplicate bug reports using the Radar links above. This is the best way to give Apple an idea of how much this is affecting our daily work. Thanks!</p>
<p><strong>Updated March 22nd, 2011:</strong> The developers of Ingredients are now <a href="http://fileability.net/ingredients/#donate">accepting donations</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2011/03/17/great-writing-terrible-reading/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mac App Store guide</title>
		<link>http://furbo.org/2011/03/09/mac-app-store-guide/</link>
		<comments>http://furbo.org/2011/03/09/mac-app-store-guide/#comments</comments>
		<pubDate>Wed, 09 Mar 2011 17:45:15 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=304</guid>
		<description><![CDATA[It&#8217;s no secret that the Mac App Store is a terrific new distribution channel for developers. Apple also provides plenty of documentation on how to prepare your app for submission.
Unfortunately, there&#8217;s not much information on how to create a product that can also be distributed through more traditional channels, such as your own product website. [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s no secret that the <a href="http://www.apple.com/mac/app-store/">Mac App Store</a> is a terrific new distribution channel for developers. Apple also provides plenty of documentation on how to <a href="https://developer.apple.com/devcenter/mac/documents/submitting.html">prepare your app for submission</a>.</p>
<p>Unfortunately, there&#8217;s not much information on how to create a product that can also be distributed through more traditional channels, such as your own <a href="http://iconfactory.com/software">product website</a>. This guide will help you update your Xcode projects to make it as simple as possible to create products for both channels simultaneously.</p>
<h3>Introduction</h3>
<p>The basic strategy is to create two build targets: one that creates everything for your own website, and another that creates the stuff Apple requires for the Mac App Store. The examples were all written using Xcode 3, but can be adapted to newer versions as needed.</p>
<p>The build target for your own website will include the Sparkle framework for doing updates. The one for the Mac App Store will create signed code that does a cryptographic check of the license receipt.</p>
<p>Note that these techniques can be used even if you&#8217;re only doing distribution on the Mac App Store: beta testers will benefit from builds that don&#8217;t require a receipt before launching.</p>
<p>To take you through the entire process, I&#8217;m going to use a real world example: I originally wrote these instructions while preparing our <a href="http://flareapp.com">Flare</a> product for release. When you see &#8220;Flare&#8221;, think &#8220;MyApp&#8221;. Likewise, &#8220;Iconfactory&#8221; will be &#8220;MyCompany.&#8221;</p>
<h3>Certificate Setup</h3>
<p>Before setting things up, make sure that you have two certificates in your keychain:</p>
<blockquote><p>
3rd Party Mac Developer Installer: The Iconfactory<br />
3rd Party Mac Developer Application: The Iconfactory
</p></blockquote>
<p>If you don&#8217;t already have these installed, you can get them from the <a href="http://developer.apple.com/certificates/index.action">Developer Certificate Utility in the Member Center</a> on the Apple Developer website.</p>
<h3>Project Settings</h3>
<p>In Project Build Settings, under Packaging, enable Info.plist preprocessing with:</p>
<pre>
Info.plist Other Preprocessor Flags: -C
Preprocess Info.plist File: Checked
</pre>
<p>Do this for both the Debug and Release configurations.</p>
<p>Why do you want to preprocess your Info.plist file? Because there are subtle differences between the settings required for the Mac App Store and your own website. You could, of course, solve the problem by having two Info.plist files, but then you run the risk of them getting out of sync: what happens when you change the version number in one file and forget to do it in the other? Keeping things like document types consistent is tedious work: it&#8217;s much easier to configure your app with a single file.</p>
<p>Since things like checking license files and expiration dates are a pain when you&#8217;re debugging code, we&#8217;ll also define a DEBUG flag in the Debug configuration:</p>
<pre>
Other C Flags: -DDEBUG
</pre>
<h3>Target Settings</h3>
<p>You&#8217;ll want to create two build targets:</p>
<blockquote><p>
Flare<br />
Flare App
</p></blockquote>
<p>It&#8217;s likely that you already have one target and can just duplicate it. The target &#8220;Flare&#8221; will be for your website, while &#8220;Flare App&#8221; is destined for the Mac App Store.</p>
<p>Make sure that both targets are using the same Info.plist source file for both the Debug and Release configurations:</p>
<pre>
Info.plist File: Flare-Info.plist
</pre>
<p>When you duplicate a target, Xcode &#8220;helpfully&#8221; creates a new Info.plist file for you. Since you&#8217;re going to be using a single file that&#8217;s customized using the preprocessor, you don&#8217;t need this second file and can delete it from the project folder.</p>
<p>It&#8217;s also important to remember that any new files that get added to the project now must be added to both targets. The goal is to keep both of them in sync.</p>
<h4>Flare</h4>
<p>In the target&#8217;s Link Binary With Libraries build phase, make sure that Sparkle.framework is included. If you&#8217;re following these steps just so you can have a beta build, leave this framework out.</p>
<h4>Flare App</h4>
<p>In Flare App&#8217;s Link Binary With Libraries build phase, make sure that Sparkle.framework is not included. You&#8217;ll want to make sure that IOKit.framework and Security.framework are included in the list (since they are used to determine the MAC address and check certificates during license verification.)</p>
<p>While you&#8217;re at it, make sure that Sparkle.framework is not in the target&#8217;s Copy Files build phase. Even if your app is not linking to Sparkle, a rejection awaits if the App Review team finds the framework in the application bundle.</p>
<p>Since we&#8217;re going to be adding code that checks which version is being built, add a new preprocessor flag to both the Debug and Release configurations for the target:</p>
<pre>
Other C Flags: -DMAC_APP_STORE
</pre>
<p>In your Objectve-C source code, you can now do things like this:</p>
<pre>
#ifdef MAC_APP_STORE
	BOOL validLicense = AppStoreLicenseCheck();
#else
	BOOL validLicense = MySuperSekretLicenseCheck();
#endif
</pre>
<p>App Store submissions must use signed code, so you&#8217;ll need set the following build setting in the Code Signing section:</p>
<pre>
Code Signing Identity: 3rd Party Mac Developer Application: The Iconfactory
</pre>
<p>You may also want to do this for the Flare target as well.</p>
<p>In the Linking section, you need to add the OpenSSL cryptographic library so the App Store license can be checked:</p>
<pre>
Other Linker Flags: -lcrypto
</pre>
<p>Do this for both the Release and Debug configurations since you&#8217;ll want to use Apple&#8217;s test_receipt while debugging your license verification code.</p>
<p>Finally, in the Target Build Settings, add the following under Packaging:</p>
<pre>
Info.plist Preprocessor Definitions: MAC_APP_STORE
</pre>
<h4>Info.plist</h4>
<p>Now you can update your Info.plist to work with preprocessor definitions. For example, the Flare-Info.plist is:</p>
<pre>
#define BUILD_VERSION 1.0
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
	&lt;key&gt;CFBundleDevelopmentRegion&lt;/key&gt;
	&lt;string&gt;English&lt;/string&gt;
	&lt;key&gt;CFBundleExecutable&lt;/key&gt;
	&lt;string&gt;${EXECUTABLE_NAME}&lt;/string&gt;
	&lt;key&gt;CFBundleIconFile&lt;/key&gt;
	&lt;string&gt;app.icns&lt;/string&gt;
	&lt;key&gt;CFBundleIdentifier&lt;/key&gt;
#ifndef MAC_APP_STORE
	&lt;string&gt;com.artissoftware.mac.flare&lt;/string&gt;
#else
	&lt;string&gt;com.artissoftware.flare&lt;/string&gt;
#endif
	&lt;key&gt;CFBundleInfoDictionaryVersion&lt;/key&gt;
	&lt;string&gt;6.0&lt;/string&gt;
	&lt;key&gt;CFBundleName&lt;/key&gt;
	&lt;string&gt;${PRODUCT_NAME}&lt;/string&gt;
	&lt;key&gt;CFBundlePackageType&lt;/key&gt;
	&lt;string&gt;APPL&lt;/string&gt;
	&lt;key&gt;CFBundleShortVersionString&lt;/key&gt;
	&lt;string&gt;BUILD_VERSION&lt;/string&gt;
	&lt;key&gt;CFBundleSignature&lt;/key&gt;
	&lt;string&gt;????&lt;/string&gt;
	&lt;key&gt;CFBundleVersion&lt;/key&gt;
	&lt;string&gt;BUILD_VERSION&lt;/string&gt;
	&lt;key&gt;LSApplicationCategoryType&lt;/key&gt;
	&lt;string&gt;public.app-category.photography&lt;/string&gt;
	&lt;key&gt;LSMinimumSystemVersion&lt;/key&gt;
#ifndef MAC_APP_STORE
	&lt;string&gt;${MACOSX_DEPLOYMENT_TARGET}&lt;/string&gt;
#else
	&lt;string&gt;10.6.6&lt;/string&gt;
#endif
	&lt;key&gt;NSHumanReadableCopyright&lt;/key&gt;
	&lt;string&gt;Copyright © 2006-2011 The Iconfactory &#038; Artis Software&lt;/string&gt;
	&lt;key&gt;NSMainNibFile&lt;/key&gt;
	&lt;string&gt;MainMenu&lt;/string&gt;
	&lt;key&gt;NSPrincipalClass&lt;/key&gt;
	&lt;string&gt;NSApplication&lt;/string&gt;
#ifndef MAC_APP_STORE
	&lt;key&gt;SUFeedURL&lt;/key&gt;
	&lt;string&gt;http://iconfactory.com/appcasts/Flare/appcast.xml&lt;/string&gt;
	&lt;key&gt;SUExpectsDSASignature&lt;/key&gt;
	&lt;true/&gt;
	&lt;key&gt;SUPublicDSAKeyFile&lt;/key&gt;
	&lt;string&gt;dsa_pub.pem&lt;/string&gt;
#endif
&lt;/dict&gt;
&lt;/plist&gt;
</pre>
<p>Note that after adding the preprocessor definitions, the file will no longer open as a property list. You&#8217;ll need to right-click on the item in the Groups &#038; Files list and select Open As > Source Code File.</p>
<p>The MAC_APP_STORE preprocessor definition allows a different bundle identifier to be selected, forces 10.6.6 as a minimum OS version, and removes the Sparkle configuration information.</p>
<h3>Distribution Targets</h3>
<p>It&#8217;s now time to automate the build of these two targets. This will be done with two aggregate build targets. Create the following:</p>
<blockquote><p>
Distribution_Iconfactory<br />
Distribution_App_Store
</p></blockquote>
<p>The first will be used for your own website and the second is for the App Store.</p>
<p>For both build targets, make sure to define the following build setting for the release configuration:</p>
<pre>
PRODUCT_NAME: Flare
</pre>
<p>This value gets used in the run scripts to generate file names.</p>
<h4>Distribution_Iconfactory</h4>
<p>The first thing in the &#8220;Distribution_Iconfactory&#8221; target should be &#8220;Flare&#8221;. After that, create a new run script build phase (right-click on &#8220;Distribution_Iconfactory&#8221; and select Add > New Build Phase > New Run Script Build Phase. Name it &#8220;Package Release&#8221;.</p>
<p>This script will create several things:</p>
<ul>
<li>A ZIP file with build results. A version number is also added to the file name.</li>
<li>A signature for the file that Sparkle will use to verify a new update.</li>
<li>An appcast file that can be uploaded to your website.</li>
</ul>
<p>The contents of the run script are as follows:</p>
<pre>
set -o errexit

[ $CONFIGURATION = Release ] || { echo Distribution target requires "'Release'" build configuration; false; }

VERSION=$(defaults read "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Contents/Info" CFBundleVersion)
DOWNLOAD_BASE_URL="http://iconfactory.s3.amazonaws.com/flare"
RELEASENOTES_URL="http://iconfactory.com/appcasts/Flare/release_notes.html#version-$VERSION"

PACKAGE_NAME=`echo "$PRODUCT_NAME" | sed "s/ /_/"`
ARCHIVE_FILENAME="$PACKAGE_NAME-$VERSION.zip"
DOWNLOAD_URL="$DOWNLOAD_BASE_URL/$ARCHIVE_FILENAME"
KEYCHAIN_PRIVKEY_NAME="Sparkle Private Key"

WD=$PWD
cd "$BUILT_PRODUCTS_DIR"
rm -f "$PRODUCT_NAME"*.zip
ditto -ck --keepParent "$PRODUCT_NAME.app" "$ARCHIVE_FILENAME"

SIZE=$(stat -f %z "$ARCHIVE_FILENAME")
PUBDATE=$(LC_TIME=en_US date +"%a, %d %b %G %T %z")

PRIVATE_KEY=$(security find-generic-password -g -s "$KEYCHAIN_PRIVKEY_NAME" 2>&#038;1 1>/dev/null | /usr/bin/perl -pe '($_) = /"(.+)"/; s/\\012/\n/g' | /usr/bin/perl -MXML::LibXML -e 'print XML::LibXML->new()->parse_file("-")->findvalue(q(//string[preceding-sibling::key[1] = "NOTE"]))')
echo "$PRIVATE_KEY" > /tmp/sparkle.key

[ -n "$PRIVATE_KEY" ] || { echo Unable to load signing private key with name "'$KEYCHAIN_PRIVKEY_NAME'" from keychain; false; }

SIGNATURE=$(openssl dgst -sha1 -binary < "$ARCHIVE_FILENAME" | openssl dgst -dss1 -sign /tmp/sparkle.key | openssl enc -base64)

echo $SIGNATURE > /tmp/sig.out

rm /tmp/sparkle.key

[ -n "$SIGNATURE" ] || { echo Unable to create signature for "'$ARCHIVE_FILENAME'"; false; }

cat > "$BUILT_PRODUCTS_DIR/appcast.xml" &lt;&lt;EOF
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle"  xmlns:dc="http://purl.org/dc/elements/1.1/"&gt;
  &lt;channel&gt;
    &lt;title&gt;Flare Release&lt;/title&gt;
    &lt;link&gt;http://iconfactory.com/appcasts/Flare/appcast.xml&lt;/link&gt;
    &lt;description&gt;Most recent version of Flare.&lt;/description&gt;
    &lt;language&gt;en&lt;/language&gt;
    &lt;item&gt;
      &lt;title&gt;Version $VERSION&lt;/title&gt;
      &lt;sparkle:releaseNotesLink&gt;$RELEASENOTES_URL&lt;/sparkle:releaseNotesLink&gt;
      &lt;pubDate&gt;$PUBDATE&lt;/pubDate&gt;
      &lt;enclosure
        url="$DOWNLOAD_URL"
        sparkle:version="$VERSION"
        type="application/octet-stream"
        length="$SIZE"
        sparkle:dsaSignature="$SIGNATURE"
      /&gt;
    &lt;/item&gt;
  &lt;/channel&gt;
&lt;/rss&gt;
EOF
</pre>
<p>(Thanks to Marc Liyange for the <a href="http://www.entropy.ch/blog/Developer/2008/09/22/Sparkle-Appcast-Automation-in-Xcode.html">original idea</a>.)</p>
<p>Before this script will work, you need to create a secure note in your Keychain named &#8220;Sparkle Private Key&#8221;. Contents should be the &#8220;DSA PRIVATE KEY&#8221; text from the dsa_priv.pem file you created when setting up Sparkle.</p>
<h4>Distribution_App_Store</h4>
<p>The first thing in this aggregate target is &#8220;Flare App&#8221;. After that build step, add this run script build phase. Name it &#8220;Package Release&#8221;:</p>
<pre>
set -o errexit

[ $CONFIGURATION = Release ] || { echo Distribution target requires "'Release'" build configuration; false; }

VERSION=$(defaults read "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Contents/Info" CFBundleVersion)

PACKAGE_NAME=`echo "$PRODUCT_NAME" | sed "s/ /_/"`
ARCHIVE_FILENAME="$PACKAGE_NAME-$VERSION.pkg"

cd "$BUILT_PRODUCTS_DIR"
rm -f "$PACKAGE_NAME"*.pkg
productbuild --component "$PRODUCT_NAME.app" /Applications \
	--sign "3rd Party Mac Developer Installer: The Iconfactory" "$ARCHIVE_FILENAME"
</pre>
<p>This script produces a .pkg installer file that&#8217;s signed with the Iconfactory&#8217;s certificate.</p>
<h3>Distribution Build Script</h3>
<p>Since both of the distribution builds create a binary in your Project&#8217;s build/Release folder, you need to remember to clean the target before building. To make this easy, just create the following shell script named &#8220;build_release&#8221;:</p>
<pre>
#!/bin/sh

current_tools=`xcode-select -print-path`
build_tools="/Developer"

switch=0
if [ $current_tools != $build_tools ]; then
	switch=1
fi

if [ $switch -ne 0 ]; then
	echo "Switching from $current_tools to $build_tools..."
	sudo xcode-select -switch $build_tools
else
	echo "Using $build_tools..."
fi

configuration="Release"

target="Distribution_App_Store"
xcodebuild \
	-configuration "$configuration" \
	-target "$target" \
	clean build

target="Distribution_Iconfactory"
xcodebuild \
	-configuration "$configuration" \
	-target "$target" \
	clean build

if [ $switch -ne 0 ]; then
	echo "Restoring $current_tools..."
	sudo xcode-select -switch $current_tools
fi
</pre>
<p>This script also ensures that you&#8217;re building with a released version of the Xcode developer tools (installed in /Developer). This is important if you do iOS development, as you&#8217;re likely to have a beta versions installed as well.</p>
<h3>Changes to App Delegate</h3>
<p>So far, we&#8217;ve been focused on building and packaging your release. You&#8217;ll also need to change your source code to accommodate the distribution channel.</p>
<p>If you haven&#8217;t done so already, make sure that there are no Sparkle objects in your MainMenu.xib file (as is suggested by the documentation.) The reason for this is simple: the App Review team does a grep for SUUpdater on binaries are submitted. If you have an archived object in the NIB file you&#8217;ll be rejected.</p>
<p>Since you&#8217;ll still need an SUUpdater object, you&#8217;ll need to create an instance of the object manually as you awake from the NIB. Since the application delegate is also on the responder chain, it can also handle the -checkForUpdates: message:</p>
<pre>
#ifndef MAC_APP_STORE
#import "Sparkle/SUUpdater.h"
#endif

- (void)awakeFromNib
{
#ifdef MAC_APP_STORE
	[[checkForUpdatesMenuItem menu] removeItem:checkForUpdatesMenuItem];
#else
	[[SUUpdater alloc] init];
#endif
}

#ifndef MAC_APP_STORE
- (IBAction)checkForUpdates:(id)sender
{
	[[SUUpdater sharedUpdater] checkForUpdates:sender];
}
#endif
</pre>
<p>You&#8217;ll also need to create a NIB outlet for the &#8220;Check for Updates…&#8221; menu item so that it can be removed from the Mac App Store version.</p>
<p>(If you have your own purchasing and registration menu items, you can handle them in a similar manner. I can guarantee you won&#8217;t get through App Review with a menu item titled &#8220;Purchase Flare…&#8221;.)</p>
<p>There are two different bundle identifiers for a single application named &#8220;Flare&#8221; (one for the version from the website and another for the Mac App Store). A user could get confused if they have both copies installed (especially if one of them is a trial version with limited functionality.) To help users with multiple versions, you should add the following code at launch to check if the one from the web site is installed alongside another from the App Store:</p>
<pre>
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
#ifndef DEBUG
#ifndef MAC_APP_STORE
	// check that a trial version isn't installed
	NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
	NSString *pathToAppStoreVersion = [workspace absolutePathForAppBundleWithIdentifier:@"com.artissoftware.flare"];
	if (pathToAppStoreVersion) {
		NSString *message = [NSString stringWithFormat:@"It looks like you have a copy of Flare from the Mac App Store installed in \"%@\".\n\nThe application you just launched is a trial version and should be removed. Would you like to quit now so you can move this unneeded file to the Trash?\n\nHint: Use the \"Move to Trash\" item in the \"File\" menu after the Finder window appears.", [pathToAppStoreVersion stringByDeletingLastPathComponent]];

		NSInteger result = [[NSAlert alertWithMessageText:@"Multiple Copies Installed" defaultButton:@"Quit and Reveal in Finder" alternateButton:@"Continue" otherButton:nil informativeTextWithFormat:message] runModal];
		if (result == NSAlertDefaultReturn) {
			[workspace selectFile:[[NSBundle mainBundle] bundlePath] inFileViewerRootedAtPath:nil];
			exit(0);
		}
	}
#endif
#endif

	…
}
</pre>
<p>If you&#8217;re using these techniques to build a beta version in parallel with your Mac App Store build, you&#8217;ll want to have some expiration checking code in the app. Otherwise, your final beta will find its way onto the Internet…</p>
<pre>
// expiration is used for any (beta) builds that aren't for the Mac App Store
#ifndef MAC_APP_STORE
#define USE_EXPIRATION 1
#else
#define USE_EXPIRATION 0
#endif
</pre>
<pre>
#if USE_EXPIRATION

- (void)checkExpiration
{
	NSDate *today = [NSDate date];

	// pick the date to expire on
	NSDate *expireDate = [NSDate dateWithString:@"2011-04-01 00:00:00 -0800"];

	NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init]  autorelease];
	[dateFormatter setDateFormat:@"h:mm a 'on' EEEE',' MMMM d',' yyyy"];
 	NSString *expireDateString = [dateFormatter stringFromDate:expireDate];

	if (! [[today laterDate:expireDate] isEqualToDate:expireDate]) {
		[[NSAlert alertWithMessageText:@"Take Five Beta" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"This beta release of Take Five expired at %@.", expireDateString] runModal];
		[[NSApplication sharedApplication] terminate:self];
	}
	else {
		[[NSAlert alertWithMessageText:@"Take Five Beta" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"This release of Take Five is a beta and will expire at %@.", expireDateString] runModal];
	}
}

#endif
</pre>
<pre>
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
…

#ifndef DEBUG
#if USE_EXPIRATION
	[self checkExpiration];
#endif
#endif
…
}
</pre>
<h3>Changes to main.m</h3>
<p>The license check for the Mac App Store should happen as early as possible in the app. It&#8217;s recommended that this happens before NSApplicationMain is called:</p>
<pre>
#import "ValidateReceipt.h"

int main(int argc, char *argv[])
{
#if MAC_APP_STORE
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	if (! validReceipt()) {
		pool = (NSAutoreleasePool *)1;
		exit(173);
	}
	[pool drain];
#endif

	return NSApplicationMain(argc, (const char **) argv);
}
</pre>
<p>The code that assigns an invalid value to the pool object is done as a simple protection against piracy. If someone tries to patch the exit(173), they&#8217;ll just be met with an objc_msgSend exception when the pool is drained.</p>
<p>Of course, you&#8217;ll want to add additional code that checks the validity of the receipt elsewhere in your code. The Apple Developer website has additional information on <a href="http://developer.apple.com/devcenter/mac/documents/validating.html#//apple_ref/doc/uid/TP40010573-CH1-SW9">how to validate your store receipts</a>.</p>
<h3>Receipt Validation</h3>
<p>As far as validating the license is concerned, the bulk of the code to parse and validate the receipt can be gotten from the <a href="https://github.com/roddi/ValidateStoreReceipt">ValidateStoreReceipt project on github</a>. You&#8217;ll need to change the hard-coded bundle identifier, version numbers and paths used in the project as you adapt this code for your own product.</p>
<h3>Testing</h3>
<p>There&#8217;s a lot going on here, so you&#8217;ll certainly want to test both the distribution builds. The builds that are going to beta testers or onto your own website are straightforward: it&#8217;s just a ZIP file that can be loaded onto the target system. Once loaded, check that menu item for Sparkle updates is present. You&#8217;ll also want to check the Package Contents to see that the correct bundle identifier is set.</p>
<p>Things get a little more complicated when you start testing the build for the Mac App Store.</p>
<p>Start by reading Apple&#8217;s instructions on <a href="https://developer.apple.com/devcenter/mac/documents/submitting.html#//apple_ref/doc/uid/TP40010572-CH16-SW7">testing the installation process</a>. Unfortunately, these instructions only show you how to get the application installed in your /Applications folder:</p>
<pre>
sudo installer -store -pkg Flare-1.0.pkg -target /
</pre>
<p>The documentation fails to mention that the installation process can fail if duplicate copies of the app are present elsewhere on the system (e.g. in the build folder.) Beta versions that use the same bundle identifier can also be a problem.</p>
<p>Apple&#8217;s test documentation also fails to mention that sandbox users accounts can be created in iTunes Connect (under Manage Users.) These user names and passwords can then be entered after launching the installed application and a receipt will be generated in the application&#8217;s _MASReceipt folder.</p>
<p>In order for this launch test to work, the app metadata must be defined in iTunes Connect (a binary does not need to be uploaded, it only needs to show up in &#8220;Manage Your Apps&#8221;.) Also make sure you sign out and quit the App Store app before launching your app to test the receipt processing code.</p>
<p>A bug report <a href="http://www.openradar.me/8869269">has been filed</a>.</p>
<h3>Conclusion</h3>
<p>Hopefully these long-winded instructions will be helpful as you prepare your release for the Mac App Store. We&#8217;ve already used them several times for <a href="http://iconfactoryapps.com">our own products</a>, so I&#8217;m guessing they will be. :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2011/03/09/mac-app-store-guide/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone multitasking</title>
		<link>http://furbo.org/2010/06/21/iphone-multitasking/</link>
		<comments>http://furbo.org/2010/06/21/iphone-multitasking/#comments</comments>
		<pubDate>Mon, 21 Jun 2010 18:08:46 +0000</pubDate>
		<dc:creator>Craig Hockenberry</dc:creator>
				<category><![CDATA[Advice]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Miscellaneous]]></category>

		<guid isPermaLink="false">http://furbo.org/?p=293</guid>
		<description><![CDATA[It&#8217;s no secret that &#8220;multitasking&#8221; is one of the great new features of iOS 4. Unfortunately, many people have a misconception about what Apple has implemented. Hopefully this short essay will help you understand the restrictions and the good reasons for having these limits.
On your desktop, multitasking means that any application or process can run [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s no secret that &#8220;multitasking&#8221; is one of the great new features of iOS 4. Unfortunately, many people have a misconception about what Apple has implemented. Hopefully this short essay will help you understand the restrictions and the good reasons for having these limits.</p>
<p>On your desktop, multitasking means that any application or process can run at the same time as another. Technically, there&#8217;s no reason why the same can&#8217;t be done on a mobile device. However, from a more practical point-of-view, there is one good reason why you don&#8217;t want this: a running app uses energy that decreases your battery life. Running fewer apps means you can listen to music longer, make more phone calls, or call up Maps at the end of the day to find a place for dinner.</p>
<p>At the same time, there are certain types of app that must run in the background in order to be useful. Apple has identified three categories of apps:</p>
<ul>
<li>Audio – Apps that plays audible content while in the background. The poster child for this type of application is Pandora.</li>
<li>VOIP – When you&#8217;re making or receiving phone calls over an Internet connection, you&#8217;re using a &#8220;Voice Over Internet Protocol&#8221; app that runs in the background. Skype is a good example.</li>
<li>Location – Some applications need to run in the background so they can keep track of your current location. An app that logs GPS coordinates while you take a walk or run would need to do this.</li>
</ul>
<p>Additionally, apps can tell iOS 4 that they need additional time to complete a task or want the user to be notified at a specific time. This lets apps finish a long download or pop up the little blue window like an incoming SMS message.</p>
<p>These simple rules cover a wide variety of situations, but there are still some cases that aren&#8217;t covered. The main shortcoming is with apps that need to periodically refresh data. Social networking apps, chat programs, news readers, and other utilities that check the Internet for changing data don&#8217;t fit into any of the above categories. Developers have <a href="http://www.marco.org/684391075">proposed solutions</a> to these problems, but there&#8217;s no solution for today&#8217;s software.</p>
<p>Part of the confusion with multitasking comes from Apple&#8217;s excellent implementation of &#8220;task switching&#8221;. When you double-tap on the home button and start another application, the previous application is &#8220;frozen&#8221; and put into a state where it&#8217;s not running but can be restarted quickly. A part of the freezing process also reduces the amount of memory being used: allowing more applications to fit in freezer.</p>
<p>The next time you tap on the app&#8217;s icon, it is &#8220;thawed out&#8221; and put back on your iPhone&#8217;s screen while the previous app is frozen. This process is repeated each time you launch an app.</p>
<p>This sleight of hand makes it feel like you&#8217;re running many more applications than you actually are. It also explains how your iPhone can continue to have great battery life while you interact with many different apps. Most of your apps will be frozen and not using power: only the app on your screen is active. And even with audio, phone or GPS apps that are running in the background, you won&#8217;t be using more than one of those at a time (go ahead and try to listen to Pandora and the iPod apps at the same time!)</p>
<p>Hopefully this short explanation helps you understand that the developer of your favorite app isn&#8217;t being lazy about doing refreshing in the background! If you feel strongly about this situation, the best thing you can do is <a href="http://www.apple.com/feedback/iphone.html">give Apple some feedback</a>.</p>
<p><strong>Updated July 1st, 2010:</strong> Matt Neuburg has written an <a href="http://db.tidbits.com/article/11378">in-depth explanation of fast app switching</a> at TidBITS.</p>
]]></content:encoded>
			<wfw:commentRss>http://furbo.org/2010/06/21/iphone-multitasking/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

