<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[iOS Examples Without Code - Medium]]></title>
        <description><![CDATA[Real-world iOS examples. You go figure out how to code them. - Medium]]></description>
        <link>https://medium.com/ios-examples-without-code?source=rss----1280784ec267---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>iOS Examples Without Code - Medium</title>
            <link>https://medium.com/ios-examples-without-code?source=rss----1280784ec267---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 13 Jul 2026 10:30:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/ios-examples-without-code" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Intermission 3]]></title>
            <link>https://medium.com/ios-examples-without-code/intermission-3-85737f8e7707?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/85737f8e7707</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[design]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Thu, 07 May 2020 20:02:03 GMT</pubDate>
            <atom:updated>2020-05-07T20:02:03.090Z</atom:updated>
            <content:encoded><![CDATA[<h4>Activate the Secret Menus.</h4><p>Now that you know we have secret features for debugging and testing, let’s consider how to activate them when we need them. But first, let’s go over a few larger issues.</p><h4>Should There Be Secret Features At All?</h4><p>There’s always a bit of discussion around this issue. The hard-core devotees will argue no, you should never have secret features in production builds. You should instead have alternative builds only available to insiders with the secret features you want. There’s plenty of validity to this viewpoint, but others take a different approach.</p><p>Having secret features, for debugging and testing, in every build, production or not, affords a high degree of convenience. You can have more or less secure modes of activation, and even add authentication if you want. Having separate builds adds complexity, and quite often confusion about who is testing what. The trade-offs are up to you.</p><p>Finally, many app developers add A/B testing into apps, which is much in the same league as secret features. So generally, the purists lose this argument in many places.</p><h4>Alternatives for Activation</h4><p>There are many possibilities for activating secret menus. The first one I ever came across was “triple tap on the copyright notice” — perhaps a gesture you would not expect the average user to try.</p><p>Another approach is to have a helper app that you install on a device where you wish to test — the helper app does nothing but register to respond to a lengthy custom URL scheme. The apps with secret features can then see if such an app is installed on device, and activate the features only if it is installed.</p><p>There are many other possibilities, which are outlined by Mr. Andrew King in a nice article. He recommends installing a custom profile on a device which apps can look for prior to activating secret features.</p><p><a href="https://andrewking.ca/2020/04/how-to-enable-custom-debugging-in-release-builds">How to Enable Custom Debugging in Release Builds - Andrew King</a></p><p>Mr. King also lists a few more ways to possibly unlock secret features, none of which are quite the way we ended up doing it.</p><h4>Tap the Rows to Unlock</h4><p>While multiple tap gestures on some UI item provides the simplest approach, it can be easily discovered, perhaps even accidentally, by average users.</p><p>What we want is a longer code, perhaps a sequence of digits, that will unlock the features we wish to have concealed from regular users, but readily available to us.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/278/1*aMQmreTtp29mnaqHXweGDQ.png" /></figure><p>An eight-digit code should be long enough to deter anyone from brute force solutions, as long as we don’t make it “12345678&quot; — let’s choose a better one “17762020.”</p><p>To enter the code, we monitor a table view, in this case our App Info details, and watch to see if a corresponding set of rows is tapped. In our case we tap</p><pre>• Bitcode Enabled?<br>• Default Compiler<br>• Default Compiler<br>• Configuration<br>• Build Date?<br>• Architecture<br>• Build Date?<br>• Architectures</pre><p>Since these rows otherwise do nothing unless tapped, the app simply does nothing at all until it recognizes the desired sequence. When it does recognize the required sequence, it silently activates the secret features.</p><p>You might ask where the secret code should be kept? For the most convenience, you store it in the app build. In a property list, in a class somewhere, whatever is convenient. If you are very paranoid, you can obfuscate it as best you can.</p><p>If you are even more paranoid, you can consider having records in CloudKit (or some other server) where you will check that the device is using an Apple ID that you have authorized to reach the secret features.</p><h4>Don’t do anything crazy</h4><p>As you will see in future stories, none of the secret features we enable in our apps with this code compromise security or potentially enable fraud. Don’t put anything that could do so in your apps.</p><h4>One more thing</h4><p>It’s convenient to have the same code that activates secret features also deactivate them.</p><p>Next up we’ll dive into the Developer menu features and see what we find there.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=85737f8e7707" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/intermission-3-85737f8e7707">Intermission 3</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Settings 108]]></title>
            <link>https://medium.com/ios-examples-without-code/settings-108-2c01e6ed3b89?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/2c01e6ed3b89</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[objective-c]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Wed, 06 May 2020 17:21:00 GMT</pubDate>
            <atom:updated>2020-05-07T20:00:11.649Z</atom:updated>
            <content:encoded><![CDATA[<h4>The Secret Menus.</h4><p>Unlike the Secret History of Procopius, our Secret Menus are not going to be an attack on the Emperor Justinian, his entourage or anyone else. They will be revealed instead as a series of tools and displays that will help you greatly improve and maintain the quality of your apps.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/446/1*MqLCDtua-CPWu_LI4iLduQ.png" /><figcaption>The Secret Menus Revealed.</figcaption></figure><p>In the course of developing or revising an app, there are two sections of extended features to be enabled:</p><h4>Developer</h4><p>The Developer section contains commands that let you change the state or behavior the app for testing purposes.</p><p>For example, you might wish to quickly delete all In-App Purchases (IAP), so you can keep testing behavior without having to continually uninstall and re-install the app.</p><p>Setting the locale of the app is another very handy command when you are working on an app that is localized for more than one country. It is much more convenient to do that immediately while the app is running, than to stop and restart.</p><h4>Diagnostics</h4><p>The Diagnostics section contains commands that let you examine the current (and past) state of the app as it is running.</p><p>As one example, you might want to look in the app’s bundle to see exactly what is being placed therein. Or look into the sandboxed file system of the app, to make sure that the app is actually saving what you think it is saving.</p><p>Further, if your app is architected to support this, you might be able to introspection on various objects in the app, so you can see their current states, and examine their past behavior.</p><p>All of this functionality does not replace console logging or close examination within the Xcode environment — but it gives you considerable power in examining the behavior of apps outside of Xcode.</p><h4>A Preview of Developer and Diagnostics</h4><p>Without further ado, let’s take a look at the Developer and Diagnostics sections</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/559/1*F0Qn7fFbLyyfHZMnyCwwvQ.png" /><figcaption>Preview of Developer and Diagnostics.</figcaption></figure><p>We’ll discuss each of the rows in these sections in a forthcoming article, but first, we’ll again digress and discuss:</p><p><strong>Intermission 3 — Activate the Secret Menus.</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2c01e6ed3b89" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/settings-108-2c01e6ed3b89">Settings 108</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Settings 107D]]></title>
            <link>https://medium.com/ios-examples-without-code/settings-107d-69ae1e88a15f?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/69ae1e88a15f</guid>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Tue, 05 May 2020 15:41:00 GMT</pubDate>
            <atom:updated>2020-05-05T15:41:00.929Z</atom:updated>
            <content:encoded><![CDATA[<h4>Your Device.</h4><p>The last row in the <strong>Info, Privacy &amp; Settings</strong> section is <strong>Your Device</strong>. While you might think this would be the end of our discussion of Settings, it’s not. There’s more to come: at the end of this story we’ll open an unexpected door.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/429/1*k4QUdnlElE0qME3zURGapw.png" /></figure><p>Tapping on the <strong>Your Device </strong>row in the <strong>Info, Privacy &amp; Support</strong> section displays a standard UITableView with a number of rows displaying information about the device in hand.</p><p>When it’s a real device, as seen here, you get a real-time view into the top level state of your device.</p><p>When it’s a simulated device, you still get the information, but some of it is a little strange as it reflects the Mac on which the simulated device is running.</p><p>This information can be helpful if you get bug or crash reports involving specific devices or versions of iOS.</p><p>Most of the information shown in <strong>Your Device</strong> is captured using Apple’s NSProcessInfo class, but some requires the UNIX functions <em>sysctl</em>, <em>sysctlByName</em>, and <em>getenv</em>. Detecting the correct model of simulator is done using the SIMULATOR_MODEL_IDENTIFIER environment variable.</p><p>As we noted above, you might think that would be the end of our discussion of Settings. Except.</p><p>Next time: <strong>Section 108 — The Secret Menus.</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=69ae1e88a15f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/settings-107d-69ae1e88a15f">Settings 107D</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Settings 107C]]></title>
            <link>https://medium.com/ios-examples-without-code/settings-107c-d390ad523846?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/d390ad523846</guid>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Mon, 04 May 2020 20:20:38 GMT</pubDate>
            <atom:updated>2020-05-04T20:20:38.918Z</atom:updated>
            <content:encoded><![CDATA[<h4>Send Us Feedback.</h4><p>This is another easy one. If you have a support e-mail address, in our case <em>support@359north.com</em>, you’ve got everything you need.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/422/1*3i5SfiiZ4RR4y1sVICcilw.png" /></figure><p>Tapping on the <strong>Send Us Feedback </strong>row in the <strong>Info, Privacy &amp; Support</strong> section displays Apple’s standard view for sending an e-mail.</p><p>You can pre-populate the email with the destination, and some informatino about the app, the user device and version of iOS, along with locale information for the user. This can be especially helpful in shortening the amount of time to needed to investigate complaints or suggestions, as they can often be specific to devices or versions of iOS.</p><p>Apple’s MFMailComposeViewController makes setting this up in the LUX framework a breeze. So you get the functionality “for free” in any app you build using your own private framework.</p><p>Next time: Section 107D — Your Device.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d390ad523846" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/settings-107c-d390ad523846">Settings 107C</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Settings 107B]]></title>
            <link>https://medium.com/ios-examples-without-code/settings-107b-e70848a5726a?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/e70848a5726a</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Fri, 01 May 2020 20:02:34 GMT</pubDate>
            <atom:updated>2020-05-01T20:02:33.809Z</atom:updated>
            <content:encoded><![CDATA[<h4>Privacy Policy.</h4><p>This is an easy one. Once Apple started requiring a privacy policy accessed via URL for all apps, you had to do all the necessary content work.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/472/1*rg3gt1_ESfyPCo0x0mrfKw.png" /><figcaption>Privacy Policy in action.</figcaption></figure><p>Tapping on the Privacy Policy row in the Info, Privacy &amp; Support section displays a webview with the proper URL.</p><p>A simple approach would be to just push a view controller containing a WKWebView, and set the URL.</p><p>For a little more dynamism, we slide up a custom view controller, using a subclass of UIPresentationController to control the animation and size, and darken the background.</p><p>This is the same custom view controller we use to present web pages in the Credits section of About This App.</p><p>Next time: Section 107C — Send Us Feedback.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e70848a5726a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/settings-107b-e70848a5726a">Settings 107B</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Intermission 2]]></title>
            <link>https://medium.com/ios-examples-without-code/intermission-2-e7596ef8e4c8?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/e7596ef8e4c8</guid>
            <category><![CDATA[design]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Thu, 30 Apr 2020 18:36:58 GMT</pubDate>
            <atom:updated>2020-05-01T20:07:51.885Z</atom:updated>
            <content:encoded><![CDATA[<h4>About that Git version…</h4><p>Keeping track of what you are doing is important. The larger the team, the more important it becomes. There are two identifiers for a specific build of an app, we’ll call them the <strong>version</strong> and the <strong>build number</strong>.</p><p>We’ve used various approaches to updating these numbers over the lifetime of an app, but have settled on a single approach that’s worked well across many apps and organizations.</p><ol><li>Manually update the <strong>version</strong>, say from 1.0 to 1.1, when you start work on a new release for the App Store.</li><li>Automatically update the<strong> build number</strong>, setting it equal to the number of Git commits since the inception of the project.</li></ol><p>This approach has a lot of benefits, but read to the end to see a situation where it is perhaps less than optimal.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/273/1*Wj7JmOQ3v29gZTtKFlFFFw.png" /><figcaption>Version info for app and framework.</figcaption></figure><p>In the example here, using our terminology, <strong>Saving Daylight </strong>is at <strong>version</strong> 1.0, <strong>build number</strong> 245, while the <strong>LUX</strong> framework is at <strong>version</strong> 1.3 and <strong>build number</strong> 232. (The app <strong>build number</strong> has the Git branch name appended, as it is a debug build, not a release build.)</p><h4>Apple Terminology</h4><p>Apple itself is not consistent in how it refers to these identifiers. On the App Store, it uses only the first identifier, 1.0, and labels it “Version.” In Xcode’s organizer window it uses both, 1.0(245) and labels it “Version.” In App Store Connect, if you create a new version it wants the first identifier and calls it “Store Version Number.”</p><p>In Xcode you set these two identifiers in the General panel of a Target. Or you can set them in the Info panel, or by editing the Info.plist file directly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/741/1*4_U6qc21xuM9bYRnmxrLVA.png" /><figcaption>Example of setting Version and Build in Xcode</figcaption></figure><p>Inside the Info.plist file there are two keys that you can set:</p><ul><li>Bundle version string (short)</li><li>Bundle version</li></ul><p>corresponding to our version and build identifiers. The Info.plist keys as see in Xcode are modified from their actual values in the property list file:</p><ul><li>CFBundleShortVersionString</li><li>CFBundleVersion</li></ul><ul><li><a href="https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring?language=objc">CFBundleShortVersionString</a></li><li><a href="https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion?language=objc">CFBundleVersion</a></li></ul><p>In days of yore, developers simply updated those Info.plist keys as needed. That approach does not scale well with larger teams, and creates some work that can be avoided.</p><h4>Source Control</h4><p>Apple’s support of source control systems has evolved over time, from Perforce/CVS/Subversion to now only supporting Git directly. We’ll discuss Git here, but you can probably adapt this approach to other systems.</p><p>If you are using a source control system, it’s natural to think that counting commits from the inception of the project would be a nice, automated way to have a monotonically increasing build number.</p><p>Getting the commit count is easy enough to do, and Apple provides a command-line tool, PlistBuddy, that makes it possible to edit values inside property lists. You can add a run script to your project</p><p>It seems simple, but there’s a catch: changing a value in Info.plist is seen by Git as a change, so your project will be seen to have uncommitted changes when you build it.</p><p>There’s a clever trick to get around this problem. Your run script does not modify the Info.plist in the source code, instead it modifies the Info.plist in the Built Product, which is not under source control. It simply runs after the compile and linking build phases.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/996/1*iUaOyl_NPDBKAdvF-W88Yg.png" /><figcaption>Modify Built Product to set build number.</figcaption></figure><p>We got the basic idea for what we do from Jared Sinclair, with most of the programming details, located here:</p><p><a href="https://jaredsinclair.com/2014/09/10/the-best-of-all-possible-xcode-a.html">Jared Sinclair</a></p><p>Once you realize that you can change CFBundleVersion “after the fact”, you realize that you can also insert or change other things in Info.plist. That’s how we capture a lot more build information, which can be very valuable as you try to coordinate multiple developers and testers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/390/1*UEAhsBgX91Osc8ucVGl1uw.png" /><figcaption>Additional captured build information.</figcaption></figure><h4>About That Small Problem</h4><p>Using commit counts to version app builds works well when unrelated apps are managed in different repositories. But if that’s not the case, watch out!</p><p>Some years ago we worked in a very large and active environment where almost everything was stored in a single Subversion repository. So if you did an incremental commit, your version number jumped from 134,245 to 135,988. Needless to say, numbers that large are hard to scan in the first place, and because all the projects are mixed together, you don’t get any sense of “rate of progress” like you do when an app is hosted in its own repository. Size matters.</p><p>Next up: Settings 107B — Privacy Policy.</p><p><a href="https://medium.com/ios-examples-without-code/settings-107b-e70848a5726a">Settings 107B</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e7596ef8e4c8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/intermission-2-e7596ef8e4c8">Intermission 2</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Settings 107A]]></title>
            <link>https://medium.com/ios-examples-without-code/settings-107a-92b10094dc18?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/92b10094dc18</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Wed, 29 Apr 2020 12:01:01 GMT</pubDate>
            <atom:updated>2020-04-29T12:01:01.088Z</atom:updated>
            <content:encoded><![CDATA[<h4>About This App.</h4><p>From the Info, Privacy &amp; Support section of Settings, we’ll now look into About This App — a collection of information useful for problem solving, and perhaps satisfying the curiosity of a few users and other developers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/427/1*nGr0j9U9UlLYFqAwKqBKlQ.png" /><figcaption>Settings view leading to About This App view</figcaption></figure><p>Tapping <strong>About This App</strong> displays a new view with two or more sections. The name of the app, in this case MirrorDay, is featured as a large navigation title.</p><h4>Credits</h4><p>Upon initial display, the view has the <strong>Credits</strong> section opened — we want to make sure that the people who have helped us along the way are featured first and prominently.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/278/1*y7QJGZ53dcQLDmq1ccsuUA.png" /><figcaption>Select any credited individual or company to visit their website.</figcaption></figure><p>Perhaps differing from Credits sections in other apps, which are rarely prominently featured, we also provide links to websites associated with the people and companies we are crediting.</p><p>For example, in this view we are showing the NSBlog website at mikeash.com, which provided years of illumination while we were honing our iOS (and macOS) skills.</p><p>There’s also an “Open in Safari” button, so you can take full advantage of viewing the sites in Safari, sharing links to articles, etc.</p><p>The list of credits is embedded in the LUX framework that is included in most of our apps. That means that providing the Credits information takes little or no work, and updating the list in the LUX framework means that all our apps, when new builds are released, feature the latest list.</p><h4>The App Build Information</h4><p>The first section of the view features the build information for the app, again in this case MirrorDay.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*G3ERx4L-gQ9yOxA9qVFkIA.png" /><figcaption>Build information for MirrorDay.</figcaption></figure><p>You can see in the example that we are looking at a build running on an iOS Simulator. A number of the rows give us clues, including:</p><ul><li>Architectures</li><li>Bitcode Enabled?</li><li>Effective Platform Name</li><li>SDK Name</li></ul><p>While we are running the app in a Simulator, this information is of minor interest.</p><p>But once we are in an environment featuring testers, multiple developers, managers, etc. being able to be very specific about what build we are using is of critical importance.</p><p>In an environment where builds can possibly come from multiple machines (individual developers, CI systems like Jenkins, or various build services in the cloud), it turns out to be quite important in some instances to know exactly where an individual build was created. Although larger shops may allow no exceptions to a policy of uploading builds to the App Store from their CI system, smaller developers may sometimes go around that policy for any number of reasons.</p><p><strong>Framework Build Information</strong></p><p>Just as app information is useful in knowing exactly what one has at hand, the exact same information about library builds is also very helpful.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/490/1*E4C8YfpLfingfvk-n9Iilg.png" /></figure><p>In the example here, you can see the build information for the <strong>LUX</strong> framework.</p><p>Note the differences here, indicating we’ve included a Release build of LUX in the simulated app.</p><p>Running in the Simulator, the information shown is a little misleading.</p><p>To successfully use frameworks in iOS apps, one has to build for multiple architectures, and then combine them into one framework.</p><p>In this case, we’re showing the information for the iOS version of the framework, not the Simulator version. This is probably what we want anyway, because when the app is uploaded to the App Store, we will strip out the unneeded x86_64 architecture. Indeed, if we don’t strip that architecture out, our upload will fail with a possibly misleading message.</p><h4>How To Get Build Information</h4><p>So where does all this information come from. A lot of it comes from Xcode environment variables, but one key piece of information, the build versions shown in the section header, comes from one very clever trick which we’ll describe in the next article, another Intermission.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=92b10094dc18" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/settings-107a-92b10094dc18">Settings 107A</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Settings 107]]></title>
            <link>https://medium.com/ios-examples-without-code/settings-107-ca129b13369b?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/ca129b13369b</guid>
            <category><![CDATA[design]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Tue, 28 Apr 2020 12:31:01 GMT</pubDate>
            <atom:updated>2020-04-28T12:31:00.922Z</atom:updated>
            <content:encoded><![CDATA[<h4>Info, Privacy &amp; Support. Everything else goes here.</h4><p>After the three major sections of Options, Permissions, and Purchases, we’re down to the rest of the story. Our last section could be called “Et Cetera”, and probably should be called “Support +” to fit alphabetically, but for the moment we’ll stick with what we’ve got. Our defense for not going alphabetical is that four items is less than the magic cognitive number 7, so users should be able to easily grasp what’s here even without a true ordering.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/273/1*mE4IwXmhTzoW-pXyZes6kA.png" /></figure><p>So what have we got in our ultimate section?</p><h4>About This App</h4><p>Tap this row to display technical information about the app, the included LUX framework, and credits with links to articles and projects which were used in building our frameworks and apps.</p><h4>Privacy Policy</h4><p>Tap this row to display a web view displaying the privacy policy on our website. The chance of anyone wanting to read your privacy policy is pretty low, but you should nevertheless make it accessible to those noble few who might actually look.</p><h4>Send Us Feedback</h4><p>Tap this row to pull up a draft email addressed to our support e-mail address. Pre-formatted, it contains basic app information that will help us provide the support you need.</p><h4>Your Device</h4><p>Finally, tap this row to see the device information that can be collected by any app running on your device. We provide this information as a convenience, and it can be handy in debugging problems that are particular to an individual device.</p><p>In the next story, Settings 107A, we’ll discuss the details of the <strong>About This App </strong>section.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ca129b13369b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/settings-107-ca129b13369b">Settings 107</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Settings 106]]></title>
            <link>https://medium.com/ios-examples-without-code/settings-106-4136ed9c1533?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/4136ed9c1533</guid>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[design]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Mon, 27 Apr 2020 12:01:01 GMT</pubDate>
            <atom:updated>2020-04-27T12:01:00.942Z</atom:updated>
            <content:encoded><![CDATA[<h4>How to display in-app purchases and check for previous purchases.</h4><p>Like Permissions, almost all the work associated with displaying, purchasing, and restoring in-app purchases can be placed in a shared framework, in our case the LUX framework. Unlike Permissions, you don’t need to interact much with the app at all. From the app’s perspective the conversation looks something like this:</p><h4>When the MirrorDay app starts up</h4><pre>App: Hey LUX, here&#39;s a list of all the product identifiers that can be purchased in this app.</pre><pre>LUX: (silently accepts and checks with Apple to get the name and price of each product.)<br></pre><h4>If the user taps Purchases in Settings</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/577/1*FtVZVL65ZXXjaPFebzLXhg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/273/1*kT8Hs0ejRxXKwO6HTM4KpQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4136ed9c1533" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/settings-106-4136ed9c1533">Settings 106</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Settings 105]]></title>
            <link>https://medium.com/ios-examples-without-code/settings-105-5bd2884a861?source=rss----1280784ec267---4</link>
            <guid isPermaLink="false">https://medium.com/p/5bd2884a861</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[design]]></category>
            <dc:creator><![CDATA[Steve Mykytyn]]></dc:creator>
            <pubDate>Fri, 24 Apr 2020 12:01:02 GMT</pubDate>
            <atom:updated>2020-04-24T12:01:02.361Z</atom:updated>
            <content:encoded><![CDATA[<h4>Permissions</h4><p>We all like free stuff. We’d all love to provide an excellent Settings experience while doing as little work as possible. Surprisingly enough, you can do that with Permissions!</p><h4>Build it the lazy way.</h4><p>One of the best parts of Apple’s iOS app environment is attention to user privacy — helped along by strictly requiring apps to receive explicit permission from users to allow access to Contacts, Calendars, Location, and other protected resources. Apps are required to provide a description of why they want access to each protected resource they wish to utilize — indexed by a specific key in the Info.plist file.</p><p>The more or less current list of possible keys for iOS looks like this:</p><pre>NFCReaderUsageDescription<br>NSAppleMusicUsageDescription<br>NSBluetoothAlwaysUsageDescription<br>NSBluetoothPeripheralUsageDescription<br>NSCalendarsUsageDescription<br>NSCameraUsageDescription<br>NSContactsUsageDescription<br>NSFaceIDUsageDescription<br>NSHealthClinicalHealthRecordsShareUsageDescription<br>NSHealthShareUsageDescription<br>NSHealthUpdateUsageDescription<br>NSHomeKitUsageDescription<br>NSLocationAlwaysAndWhenInUseUsageDescription<br>NSLocationUsageDescription<br>NSLocationWhenInUseUsageDescription<br>NSMicrophoneUsageDescription<br>NSMotionUsageDescription<br>NSPhotoLibraryAddUsageDescription<br>NSPhotoLibraryUsageDescription<br>NSRemindersUsageDescription<br>NSSiriUsageDescription<br>NSSpeechRecognitionUsageDescription</pre><p>Recall that we’re handling this in our framework, and you’ll realize that all we need to do to assemble our list of relevant permissions is to look in our apps Info.plist for any of these keys! That’s pretty lazy!</p><p>For our forthcoming Saving Daylight app, we show a list of permissions like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/274/1*Ogi5Qv_gxgsuCmNv71aMrw.png" /></figure><p>You see that we have granted permissions to access <strong>Contacts</strong> and <strong>Location</strong>. But there are two items in the list of Permissions that are not in the list of keys above: <strong>iCloud</strong> and <strong>Notifications</strong>. These two are a little different.</p><p>You’ll want to know if the user is signed in to <strong>iCloud</strong> for a number of reasons — one being that signed-in users can read from and write to Apple’s CloudKit, while users who are not signed in can only read.</p><p><strong>Notifications</strong> are special in that Apple provides the text shown to the user when permission to allow them is requested. In both cases, there is no key to be found. So these two special cases are always inserted into the list of Permissions.</p><h4>Avoid Two-step Permissions Requests</h4><p>It was fashionable for a while amongst iOS developers to provide two-step permissions requests: a preliminary request asking if the user was willing to grant permission, followed by the “official” Apple request. In retrospect this was a clumsy solution and ignored the downstream ill effects of the user denying permission on the official request.</p><p>A better approach is just to ask for permission when the user attempts to perform an operation requiring that permission. If granted, everything is fine. If not, present a dialog explaining that permission is required and offering to take the user to the correct spot in Apple’s Settings app to rectify the situation.</p><h4>One Stop Shop</h4><p>The Permissions section as presented here is a “one-stop shop” for everything permission related. The app user can see the status of all permissions, and change them if necessary. Here’s an example of that in action:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/557/1*5z5X310k0tjV0yf0_px8hg.png" /></figure><p>That’s all for Permissions. Next up: Settings 106: How to display in-app purchases and check for previous purchases.</p><p>To start at the beginning of iOS Examples Without Code:</p><p><a href="https://medium.com/ios-examples-without-code/prologue-0-58cce1fca5a6">Prologue 0</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5bd2884a861" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ios-examples-without-code/settings-105-5bd2884a861">Settings 105</a> was originally published in <a href="https://medium.com/ios-examples-without-code">iOS Examples Without Code</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>