<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[xcode - Curtis Herbert]]></title><description><![CDATA[xcode - Curtis Herbert]]></description><link>https://blog.curtisherbert.com/</link><image><url>https://blog.curtisherbert.com/favicon.png</url><title>xcode - Curtis Herbert</title><link>https://blog.curtisherbert.com/</link></image><generator>Ghost 4.32</generator><lastBuildDate>Fri, 15 Nov 2024 19:00:04 GMT</lastBuildDate><atom:link href="https://blog.curtisherbert.com/tag/xcode/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Automated Xcode Build Numbers, Early 2019 Edition]]></title><description><![CDATA[Thanks to a suggested edit from friend-of-the-blog Todd Heasley I can say that, for now, the automated git-based build number script I've been working on perfecting for years is finally, dare I say it, perfect.]]></description><link>https://blog.curtisherbert.com/automated-xcode-build-numbers-early-2019-edition/</link><guid isPermaLink="false">5c9cf41c09963870cc11add7</guid><category><![CDATA[xcode]]></category><dc:creator><![CDATA[Curtis herbert]]></dc:creator><pubDate>Thu, 28 Mar 2019 16:50:55 GMT</pubDate><content:encoded><![CDATA[<p>Thanks to a suggested edit from friend-of-the-blog Todd Heasley I can say that, <em>for now,</em> the automated git-based build number script I&apos;ve been working on perfecting for <em>years</em> is finally, dare I say it, perfect.</p><p>(<a href="https://blog.curtisherbert.com/automated-build-numbers/">Where it all started in 2015</a>, the <a href="https://blog.curtisherbert.com/watchkit-app-versioning/">Watch update</a>, and <a href="https://blog.curtisherbert.com/automated-xcode-build-numbers-late-2016-edition/">almost perfect in 2016</a>)</p><p>The 2016 version of my build number system was so close to what I wanted &#x2013; it automated my build numbers for every target based on the git commit count and kept my git history clean (no build number bumps in source control). It worked almost everywhere ... except Siri extensions. For those it would never increment the build number before the Info.plist was copied. Which was inconsequential from a production standpoint, in the wild for all intents and purposes it was great. The only issue was you&apos;d always get a warning about mis-matched build numbers on upload, and more annoyingly, an email with the same warning too.&#x200C; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; </p><figure class="kg-card kg-image-card"><img src="https://blog.curtisherbert.com/content/images/2019/03/Screen-Shot-2019-03-28-at-12.29.53-PM-1.png" class="kg-image" alt loading="lazy"></figure><p>So the change that made it work now without warnings on upload? Oh, it was so devilishly simple. </p><p>Make the build number edit in the build folder, not in your source on the original Info.plist. &#x1F926;&#x200D;&#x2642;&#xFE0F;</p><!--kg-card-begin: markdown--><pre><code>git=`sh /etc/profile; which git`
bundleVersion=`&quot;$git&quot; rev-list --all |wc -l`
/usr/libexec/PlistBuddy -c &quot;Set :CFBundleVersion $bundleVersion&quot; &quot;${TARGET_BUILD_DIR}/${INFOPLIST_PATH}&quot;
</code></pre>
<!--kg-card-end: markdown--><p>As a byproduct of this change, this also lets you remove the Clear Build Number phase from my 2016 solution as the script never touches your source-controled Info.plist.</p><h2 id="setup-guide">Setup Guide</h2><p>For those who haven&apos;t been following along with my struggles, getting started with this build number automation is super simple. For every target you have that gets shipped to App Store Connect, add a build script phase (with an appropriate title like Set Build Number) and copy and past the above code into the script block. </p><p>So your targets will look something like this:</p><figure class="kg-card kg-image-card"><img src="https://blog.curtisherbert.com/content/images/2019/03/Screen-Shot-2019-03-28-at-12.38.54-PM.png" class="kg-image" alt loading="lazy"></figure><p>And that&apos;s it! Enjoy.</p>]]></content:encoded></item><item><title><![CDATA[WatchKit App Automated Build Numbers]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I wrote <a href="https://blog.curtisherbert.com/automated-build-numbers/">previously</a> about how I set up automated build numbers that were source-control friendly and didn&apos;t require a build server.</p>
<p>Unfortunately WatchKit apps (unlike WatchKit extensions) don&apos;t have build phases exposed in Xcode, so things get tricky.</p>
<p>After a month of trying I couldn&apos;</p>]]></description><link>https://blog.curtisherbert.com/watchkit-app-versioning/</link><guid isPermaLink="false">597e0854b3f09c242028539d</guid><category><![CDATA[watchkit]]></category><category><![CDATA[xcode]]></category><dc:creator><![CDATA[Curtis herbert]]></dc:creator><pubDate>Sat, 11 Apr 2015 03:42:46 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I wrote <a href="https://blog.curtisherbert.com/automated-build-numbers/">previously</a> about how I set up automated build numbers that were source-control friendly and didn&apos;t require a build server.</p>
<p>Unfortunately WatchKit apps (unlike WatchKit extensions) don&apos;t have build phases exposed in Xcode, so things get tricky.</p>
<p>After a month of trying I couldn&apos;t find a way to get automated numbering working through build scripts in the project itself. It always resulted in code signing errors as the best you could do with phases was change the number after the fact. I ended up having to fall back to using <code>agvtool</code> during release builds to manually bump (or at least using <a href="https://fastlane.tools">Fastlane</a>, automatically bump) build numbers.</p>
<p>Then a friend pointed me in the right direction.</p>
<h2 id="manuallyeditingpbxprojforfunandprofit">Manually editing .pbxproj for fun and profit</h2>
<p>While the UI isn&apos;t exposed, you can still add build phases to the project file for a watchkit app.</p>
<p><mark>Please back up your project first. You&apos;ll be manually editing the Xcode project file here.</mark></p>
<p>In your app&apos;s folder right click the project file and show package contents. Then open <code>project.pbxproj</code> in your favorite text editor.</p>
<p><strong>Step 1:</strong> We need to add a new build phase manually. I&apos;d recommend you complete my previous tutorial first so you have existing phases for automating your build number that you can just duplicate.</p>
<p>Search the file for &quot;CFBundleVersion&quot;, part of the script from the last tutorial. You should see it in a block like this left over from my last tutorial:</p>
<pre><code>81B5AC951B0A816900E3CD52 /* Build Number */ = {
  isa = PBXShellScriptBuildPhase;
  buildActionMask = 2147483647;
  files = (
  );
  inputPaths = (
  );
  name = &quot;Build Number&quot;;
  outputPaths = (
  );
  runOnlyForDeploymentPostprocessing = 0;
  shellPath = /bin/sh;
  shellScript = &quot;git=`sh /etc/profile; which git`\nbranch_name=`$git symbolic-ref HEAD | sed -e &apos;s,.*/\\\\(.*\\\\),\\\\1,&apos;`\ngit_count=`$git rev-list $branch_name |wc -l | sed &apos;s/^ *//;s/ *$//&apos;`\nsimple_branch_name=`$git rev-parse --abbrev-ref HEAD`\n\nbuild_number=\&quot;$git_count\&quot;\n\nplist=\&quot;${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\&quot;\ndsym_plist=\&quot;${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\&quot;\n\n/usr/libexec/PlistBuddy -c \&quot;Set :CFBundleVersion $build_number\&quot; \&quot;$plist\&quot;\nif [ -f \&quot;$DSYM_INFO_PLIST\&quot; ] ; then\n/usr/libexec/PlistBuddy -c \&quot;Set :CFBundleVersion $build_number\&quot; \&quot;$dsym_plist\&quot;\nfi&quot;;
};
</code></pre>
<p>Copy and paste that block to duplicate it right below the first one, and then change the ID (<code>81B5AC951B0A816900E3CD52</code> in my case) to something unique. I just changed the ending 2 to a 1. Do a quick search with the new ID to make sure you didn&apos;t accidentally pick an ID that&apos;s already been used elsewhere in the file.</p>
<p>Remember this ID you just made, we need it for step 2.</p>
<p><strong>Step 2:</strong> We need to add a new build phase to the watchkit app. Do a search on the file for &quot;com.apple.product-type.application.watchapp&quot; to find the config used by the watchkit app. It&apos;ll look like this:</p>
<pre><code>81B0136E1A6ABD5C0080C8C5 /* WatchKit App */ = {
	isa = PBXNativeTarget;
	buildConfigurationList = 81B013841A6ABD5C0080C8C5 /* Build configuration list for PBXNativeTarget &quot;WatchKit App&quot; */;
	buildPhases = (
		81B0136D1A6ABD5C0080C8C5 /* Resources */,
	);
	buildRules = (
	);
	dependencies = (
	);
	name = &quot;WatchKit App&quot;;
	productName = &quot;Slopes WatchKit App&quot;;
	productReference = 81B0136F1A6ABD5C0080C8C5 /* WatchKit App.app */;
	productType = &quot;com.apple.product-type.application.watchapp&quot;;
};
</code></pre>
<p>Add a new line to the build phases using the ID of the phase you created from the last step.</p>
<pre><code>buildPhases = (
  81B5AC951B0A816900E3CD51 /* Build Number */,
  81B0136D1A6ABD5C0080C8C5 /* Resources */,
);
</code></pre>
<p>At this point you can save and run and have automated build numbers working for your watchkit app too, satisfying Xcode 6.3&apos;s requirement that all your targets must share the same build number.</p>
<p>Big thanks to Conrad Kramer for getting me thinking in the right direction.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Automated build numbers in Xcode]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Build numbers are one of those things that we just have to deal with while writing software, but it usually provides little benefit to end-users. Much like a git commit hash, it&apos;s best left to the computers to generate for us. Lets talk about automating build numbers out</p>]]></description><link>https://blog.curtisherbert.com/automated-build-numbers/</link><guid isPermaLink="false">597e0854b3f09c242028539b</guid><category><![CDATA[xcode]]></category><dc:creator><![CDATA[Curtis herbert]]></dc:creator><pubDate>Tue, 03 Feb 2015 16:06:30 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Build numbers are one of those things that we just have to deal with while writing software, but it usually provides little benefit to end-users. Much like a git commit hash, it&apos;s best left to the computers to generate for us. Lets talk about automating build numbers out of our lives.</p>
<p>Before digging into the <em>how</em>, lets define what I&apos;m trying to achieve though automation:</p>
<ul>
<li>I want the version number (1.5.1) to be manually updated as I see fit as it is largely a marketing aspect, not a technical one. I&apos;ll usually do this on the release branch when I start a new version.</li>
<li>I want the build number (1086) to be set automatically based on the number of commits, on the current branch in git, at the time of the build.</li>
<li>I want the build number to include the branch name (1086-secret-feature-x) if we aren&apos;t building a binary for the App Store.</li>
<li>I want the build numbers to be updated without any affect on my source control.</li>
</ul>
<p>That last one is a bugger.</p>
<h2 id="myoldwayusinganinfoplistpreprocessor">My old way - Using an Info.plist preprocessor</h2>
<p>A few years ago I invested a little time automating build numbers for my apps in Xcode. Like many I stumbled upon <a href="http://www.cimgf.com/2011/02/20/revisiting-git-tags-and-building/">this post</a> from Cocoa is my Girlfriend that leverages info.plist preprocessing and git.</p>
<p>His method takes advantage of being able to define variables in a header file which Xcode will use to automatically replace values in your info.plist file. Just add a build script to keep the value in that header file up-to-date based on the number of git commits and you have automated build numbers. Pretty simple to get working.</p>
<p>Where it falls apart is how that header file affects your source control checkins. Every build will dirty the header. If you don&apos;t want to dirty your git repo with checkins on this file you&apos;d need to do something like <code>git update-index --assume-unchanged Source/InfoPlist.h</code> or add it to the .gitignore to make sure it isn&apos;t ever checked in (after you check in a dummy file the first time so people who checkout the repo don&apos;t get errors), but that falls apart quickly if you&apos;re switching branches a lot.</p>
<p>(I&apos;ve been trying <a href="http://nvie.com/posts/a-successful-git-branching-model/">git-flow</a> in <a href="http://www.git-tower.com">Tower</a> recently, which makes heavy usage of branches)</p>
<p>You also run into issues with caching as Xcode tries to cache your info.plist file in between builds and doesn&apos;t always re-trigger the pre-processing. This can be a little frustrating when you&apos;d archive without remembering to do a clean first.</p>
<h2 id="mynewwaygettingdirtywithplistbuddy">My new way - getting dirty with PlistBuddy</h2>
<p>If we can&apos;t rely on Xcode to update the plist file for us we&apos;ll have to do it ourselves. Here is the script in its entirety:</p>
<pre><code>git=`sh /etc/profile; which git`
branch_name=`$git symbolic-ref HEAD | sed -e &apos;s,.*/\\(.*\\),\\1,&apos;`
git_count=`$git rev-list $branch_name |wc -l | sed &apos;s/^ *//;s/ *$//&apos;`
simple_branch_name=`$git rev-parse --abbrev-ref HEAD`

build_number=&quot;$git_count&quot;
if [ $CONFIGURATION != &quot;Release&quot; ]; then
	build_number+=&quot;-$simple_branch_name&quot;
fi

plist=&quot;${TARGET_BUILD_DIR}/${INFOPLIST_PATH}&quot;
dsym_plist=&quot;${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist&quot;

/usr/libexec/PlistBuddy -c &quot;Set :CFBundleVersion $build_number&quot; &quot;$plist&quot;
if [ -f &quot;$DSYM_INFO_PLIST&quot; ] ; then
	/usr/libexec/PlistBuddy -c &quot;Set :CFBundleVersion $build_number&quot; &quot;$dsym_plist&quot;
fi
</code></pre>
<p>This makes all the needed build number changes in the build directory itself, so there is no affect on your source-controlled files.</p>
<p>One item of note: it was important to not forget the dSYM  info.plist in a script like this (dSYM is the file that stores the debug symbols for your app to help you track down crashes). Leaving that update out will cause HockeyApp, for one, to complain at the mis-match between the build number in the app and the build number in the debug symbols. I&apos;m not sure if this mis-match would affect crash logs in iTunes Connect, too, I never let it get that far.</p>
<h2 id="howtoinstallthisscript">How to install this script</h2>
<p><img src="https://blog.curtisherbert.com/content/images/2015/02/Screen-Shot-2015-02-01-at-5-20-58-PM.png" alt="Xcode screenshot" loading="lazy"></p>
<ul>
<li>Select your project at the top of the navigator on the left</li>
<li>Select the target you&apos;d like to enable automatic build numbers for</li>
<li>Select build phases</li>
<li>From the menu select Editor -&gt; Add Build Phase -&gt; Add Run Script Build Phase</li>
<li>Copy and paste the above script</li>
<li>Drag the build phase you added to re-order it to be just after the Copy Bundle Resources step</li>
</ul>
<p>For good measure I&apos;ll usually go into where you normally define the build number (under General for the target) and set it to &quot;UKNOWN.&quot; I&apos;ve never had the script fail, but I&apos;m always paranoid and want to see something obviously wrong if it does.</p>
<p>And, by the way, this can work for any executable target type except Watchkit Apps. This means you can synchronize your build numbers across your app target and any extensions you may have.</p>
<p>I&apos;m looking for a way to easily synchronize <em>version</em> numbers across targets, haven&apos;t gotten there yet.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Unique icons for debug, beta, and App Store builds in Xcode 5]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>During development of <a href="http://getslopes.com">Slopes</a> I decided to refine my Xcode project setup to gracefully allow for multiple versions of my app to exist on-device at the same time. Dev/staging/production is a familiar concept to most software developers, and really it&#x2019;s surprising it isn&#x2019;t a</p>]]></description><link>https://blog.curtisherbert.com/unique-icons-for-debug-beta-and-app-store-builds-in-xcode-5/</link><guid isPermaLink="false">597e0854b3f09c2420285398</guid><category><![CDATA[xcode]]></category><dc:creator><![CDATA[Curtis herbert]]></dc:creator><pubDate>Wed, 18 Sep 2013 05:25:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>During development of <a href="http://getslopes.com">Slopes</a> I decided to refine my Xcode project setup to gracefully allow for multiple versions of my app to exist on-device at the same time. Dev/staging/production is a familiar concept to most software developers, and really it&#x2019;s surprising it isn&#x2019;t a default setup in Xcode.</p>
<p>Simon Wolf posted <a href="http://swwritings.com/post/2013-05-20-concurrent-debug-beta-app-store-builds">a great article</a> earlier this year on setting up an XCode project to support multiple builds, while having to maintain only a single target. In his article Simon goes over how to make sure each build generates an app with a unique display name (&#x201C;Slopes &#x3B2;&#x201D; for a beta build, for example), all of which can be installed on-device simultaneously.</p>
<p>But I&#x2019;ve found that the name isn&#x2019;t enough. I, and my testers, have had a difficult time differentiating between the builds on name alone. I wasn&#x2019;t the biggest fan with his suggestion where one could use the notification badge as an additional visual indicator. I wanted to customize the icon.</p>
<p>Pre-Xcode 5 using a single target prevented me from customizing the app&#x2019;s icon per build (without annoying build scripts). Fortunately with the introduction of media assets in Xcode 5 there&#x2019;s a way now.</p>
<p>Before you start, spend some time in Photoshop to generate an app icon for each build you want to customize. I created unique icons for my dev and beta builds.</p>
<p><img src="https://blog.curtisherbert.com/content/images/2015/02/giant.jpg" alt="Application icons" loading="lazy"></p>
<p>Feel free to reuse the <a href="https://s3.amazonaws.com/consumedbycode/downloads/Icons+Template.zip">PSD I made</a> for dev and beta badges. It&#x2019;s based on the icon template from <a href="http://appicontemplate.com">appicontemplate.com</a>.</p>
<h2 id="multipleiconsusingmediaassets">Multiple icons using media assets</h2>
<p>If you&#x2019;re migrating from an Xcode 4 project and you haven&#x2019;t migrated your app icons to media assets yet, you need to do so. Apple makes this switch easy: go to your main target&#x2019;s general info and hit the use media assets button next to your existing app icon. This will copy your existing app icons into a media asset folder in your project. You&#x2019;ll see one asset in there called <code>AppIcon</code>.</p>
<p>If your project started in Xcode 5, using media assets for your app icon will be the default. You&#x2019;ll already see an asset called <code>AppIcon</code> in your catalog.</p>
<p>With the your app&#x2019;s media asset catalog selected from the project navigator on the left go the system menu and select Editor-&gt;New App Icon. Rename this new icon set to <code>AppIconDev</code> and drag in your customized app icons for your dev build. Do the same thing for another new app icon you&#x2019;ll call <code>AppIconBeta</code>.</p>
<p><img src="https://blog.curtisherbert.com/content/images/2015/02/giant-2.jpg" alt="Multiple icons with media assets" loading="lazy"></p>
<p>With your icons set up, the last step is to tell Xcode which icon set to use for each build. Head over to the build settings for your target and look for the setting called &#x201C;Asset Catalog App Icon Set Name&#x201D; under the Asset Catalog Compiler group.</p>
<p>Right now the icon set name should be set to <code>AppIcon</code> for all your configurations. That&#x2019;s fine for our App Store build but we need to change the name for the dev and beta builds.</p>
<p>If you followed Simon&#x2019;s article you can expand that setting to see you can specify the app icon set for three configurations: debug, release, and beta (or &#x201C;adhoc&#x201D; in Simon&#x2019;s setup). If you didn&#x2019;t follow his article, I&#x2019;d really recommend you go do that and get unique names and bundle IDs set up for your three builds.</p>
<p>Set the icon set name for debug to <code>AppIconDev</code> and set the name for beta to <code>AppIconBeta</code>. Least the icon set name for release the same.</p>
<p><img src="https://blog.curtisherbert.com/content/images/2015/02/giant.png" alt="App Icon set name samples" loading="lazy"></p>
<h2 id="bonusround">Bonus Round</h2>
<p>Similar to how Simon avoided hard-coding the app name and bundle ID by using two custom build settings, <code>BUNDLE_ID_SUFFIX</code> and <code>BUNDLE_DISPLAY_NAME_SUFFIX</code>, you can avoid hard-coding the app icons names with a third suffix: <code>BUNDLE_ICON_SET_SUFFIX</code>. With that in place you can set the icon set name setting to <code>AppIcon${BUNDLE_ICON_SET_SUFFIX}</code> for all three configurations.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>