<?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[Stories by Sam Dods on Medium]]></title>
        <description><![CDATA[Stories by Sam Dods on Medium]]></description>
        <link>https://medium.com/@sdods?source=rss-195b086ce5f4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*_WWgjlAwyk6fEMH0VsX2iQ.jpeg</url>
            <title>Stories by Sam Dods on Medium</title>
            <link>https://medium.com/@sdods?source=rss-195b086ce5f4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 06 May 2026 18:20:32 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@sdods/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[When Will The Web Replace Native Mobile Apps? (Part II)]]></title>
            <link>https://medium.com/kinandcartacreated/when-will-the-web-replace-native-mobile-apps-part-ii-92ee050bbaf1?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/92ee050bbaf1</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[progressive-web-app]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Wed, 24 Jun 2020 09:43:30 GMT</pubDate>
            <atom:updated>2020-06-24T09:43:30.642Z</atom:updated>
            <content:encoded><![CDATA[<h4>Where does mobile web currently fall short and what innovation is on the horizon that will allow it to succeed?</h4><p>In <a href="https://medium.com/p/5408c895c8a6">Part I</a>, I looked at why apps have been necessary on mobile devices — despite <a href="https://youtu.be/ubm2dYzoDW8?t=4510">Apple’s original vision</a> of iPhone apps being powered by web technology — and I looked at the current state of PWA capabilities for each mobile platform.</p><p>Now I want to look at why I won’t yet advocate web technology in place of mobile apps, for most use cases, and the innovations I predict will change that opinion in years to come.</p><h3>Current limitations of PWAs</h3><p>There are a number of reasons why PWAs aren’t yet ready to replace native mobile apps.</p><p>One overarching reason is the unwillingness of Apple to support PWAs to their fullest.</p><p>It’s funny to <a href="https://youtu.be/ubm2dYzoDW8?t=4510">watch Steve Jobs’ original announcement</a>. Now it seems Apple is actively trying to stunt the progress of web technology by preventing access to hardware and not supporting notifications.</p><p>This is an important consideration. iOS has 26% market share worldwide, but it’s over 50% in North America and many European countries, some of the largest app-revenue regions. A lot of users will suffer if you develop a PWA that lacks functionality due to Apple’s restrictions.</p><p>Below are additional considerations that may make a PWA unsuitable for some types of app, regardless of the operating system they run on:</p><ol><li>Limited device integration</li><li>Limitations of data storage and cache</li><li>Restricted background functionality</li><li>Impact on user interface</li><li>App sales and in-app purchases not possible</li><li>Lack of watch, widget or peripheral integration</li></ol><p>Let’s dive into a bit more detail on each of the considerations above.</p><h4><strong>1. Limited device integration</strong></h4><p>It’s not only iOS that restricts hardware and OS integration. The web is always playing catch up to device hardware. Google promotes the development of PWAs, but, given the large number of device manufacturers, it’s not always the case that the hardware, OS and website play nicely together.</p><p>There are still features that a web app can’t access even on Android. NFC, biometrics, geo-fencing are a few. Access to some OS features such as composing messages is also unavailable, although support in this area is evolving rapidly.</p><h4><strong>2. Limitations of data storage and cache</strong></h4><p>Like all aspects of PWAs, data storage and caching are handled differently per browser and are restricted to a percentage of device capacity, which makes them difficult to rely on. Most browsers allow enough data to be stored for the majority of use cases (e.g. up to 5GB on 128GB device), but Safari places stricter limits. Up to ~500MB of database storage is allowed, but cache is limited to ~50MB. Both may be cleared by iOS at any point, so must be treated as a temporary and not relied upon.</p><p>For developers to rely on PWAs to provide the best user experience, they need to know they can rely on data storage when needed. This is particularly important for apps that download and store locally lots of large files, such as images, videos, audio or PDFs.</p><p>Furthermore, I think the offline ability of a PWA is a gimmick. Even most native apps require an internet connection to offer much value, and promising your users offline availability will only lead to disappointment when they discover parts of the app that are not cached.</p><h4><strong>3. Restricted background functionality</strong></h4><p>Chrome allows PWAs to wake up in the background to carry out network activity and processing. However, other browsers do not support background processing and even on Android with Chrome, background functionality is not as extensive as it is for native apps.</p><p>For example, accessing the user’s location is not supported in the background.</p><p>Maintaining Bluetooth connections is not possible in the background (or even between page loads), regardless of operating system or browser.</p><p>Voice-over-IP does not integrate with the incoming call facility like it does for native apps.</p><p>iOS prevents any background processing at all. This means local notifications aren’t supported, background audio is not supported, and background network activity and other processing is not possible.</p><h4><strong>4. Impact on user interface</strong></h4><p>There remains an issue of responsiveness of web vs. non-web. By non-web, I mean native apps and apps developed using other cross-platform technologies beside web. And by responsiveness, I mean the speed with which you feel the result of any interaction.</p><p>Delays might be seen when reloading previous screens (pages) when navigating back, or controls might become unresponsive at times. Animated transitions, which are often used to maintain orientation within context, are not as prevalent or are jerky in web apps.</p><p>All new “screens” (or “views”) are loaded in place and standard browser forward/back navigation is supported. However other app navigation techniques, such as modal presentations/overlays, are not supported in the same way as they are by native apps. (Although, admittedly, this is the web, so anything is technically possible.)</p><h4><strong>5. App sales and in-app purchases not possible</strong></h4><p>A big one is monetisation. App Store distribution, whether on iOS or Android, has given developers an easy way to make money from paid apps and in-app purchases. Users already have an account setup that removes the friction of paying a developer for their software. They can easily pay for an app at point of download, or later to unlock premium functionality.</p><p>Paying for a digital product on the web is not so straightforward. It requires a developer to implement their own payment mechanism, albeit through a third party. It will also most likely require some sign up process to verify in the future that a user has paid. Apple’s App Store and Google’s Play Store handle all of that, making it simple for the developer and the consumer.</p><p>This will be a major blocker for businesses that make money directly from the software (rather than using their software as a platform for the sale of physical goods).</p><h4><strong>6. Lack of watch, widget or peripheral integration</strong></h4><p>It’s not currently possible to provide an Android widget as part of a PWA and, as you might expect, the same is true for iOS. It’s also not possible for a PWA running on iOS to interact with the Apple Watch, nor can a PWA running on Android interact with an Android Wear app. Because Bluetooth connections cannot be maintained in the background, it’s also difficult to work with third-party devices from PWAs.</p><p>If integration with watches, providing widgets, or possibly integrating with other devices (think: eyewear or in-home technology) is part of your user experience, then a PWA will not be suitable at this time.</p><h3>Innovation guaranteed</h3><p>PWAs have only been around for five years and already they are closing the gap on native app capabilities.</p><p>A lot is guaranteed to change in the next few years.</p><p>PWAs will become more powerful and iOS will catch up, to some extent, or lose out.</p><p>Here’s a few of the innovations that I predict will make web apps a truly viable alternative to native mobile apps.</p><h4><strong>1. 5G will void the issue of storage</strong></h4><p>Already, the ability of apps to store large amounts of data locally is becoming redundant. Most document or media apps rely on cloud storage anyway. For example, the thousands of photos and videos on my phone aren’t actually stored on my phone.</p><p>The availability of 5G will mean it’s even less necessary to ever store files locally, because to access them remotely will be just as fast. It’s also much easier to increase remote storage capacity when you need it, than to increase the storage capacity of your phone (i.e. buy a new phone).</p><p>There are cases when local storage is still desirable, such as for downloading music or movies for a flight. But the next decade could easily see free, fast Wi-fi on all flights and in other areas where cellular internet is not available.</p><h4><strong>2. Games will all be cloud-based</strong></h4><p>It might seem like high-end games would always be distributed as apps rather than as websites. But already we’re seeing streaming services for games that compete with downloaded and installed equivalents. Google’s Stadia is one platform that streams games in 4K at 60FPS, with no game download required.</p><p>The further benefit of cloud gaming is that users don’t need powerful devices. They just need a high speed internet connection. The web is used extensively for streaming videos so lends itself perfectly to streaming games that would otherwise be distributed as apps.</p><h4><strong>3. Access to hardware and OS features will be unrestricted</strong></h4><p>Google and Microsoft actively promote PWA development and the evolution of PWA capabilities. So it seems logical that standards will emerge for web APIs to provide deeper hardware and OS integration. iOS will of course lag behind, but there will be pressure on Apple to play catch-up — to find ways of loosening restrictions while still maintaining the user privacy Apple prides itself upon.</p><p>Interestingly, iOS Safari AutoFill is one feature that has advanced for the web quicker than for apps. Website developers can tag elements for password or payment card entry and Safari will auto-populate. Password AutoFill was extended to apps as of iOS 12 (2018), but automatically filling payment card details is not currently available to apps.</p><h4><strong>4. User interface will become as fluid as native apps</strong></h4><p>This is possibly the most obvious, but arguably the most contentious. A lot of native ambassadors will argue that a web experience will never be on par with that or a native app.</p><p>But if you look at advancements in web technology since the birth of the iPhone, combined with increased OS support bringing PWAs closer to a native look and feel, one could argue that it’s inevitable that web apps will eventually be indistinguishable from native apps in terms of user interface.</p><h4><strong>5. Distribution and payment will be streamlined</strong></h4><p>The Google Play Store already supports the distribution of PWAs, although not paid-for. Given Apple’s original vision for iPhone apps to be web apps, it would be nice to think that one day the App Store might distribute PWAs.</p><p>However, consider a trusted third party getting in on the action.</p><p>Imagine a single, platform-independent store that would allow you to browse and discover apps.</p><p>This store could provide its own authentication and user management, allowing developers to integrate an in-app purchase service. This could make the need for paid-for apps redundant. (Paid-for apps are increasingly less common already, in favour of the freemium model.)</p><p>This would render Apple’s and Google’s in-app purchase services unnecessary, but still provide users with piece of mind and security.</p><p>But if a third party was to offer such a service, it would require global clout to be worthy of implementation by developers and trust amongst end users. <em>Did someone say Microsoft?</em></p><p>These are only predictions. Nothing is guaranteed, except, of course, progress. There <em>will</em> be progress in this area, and I think it’s fair to assume <em>many</em> of these advancements will happen in the next five years.</p><h3>Closing thoughts</h3><p>What would be the downsides of PWAs taking over? Security, perhaps? Can PWAs ever be as secure as native apps? Where there’s a will, there’s a way. It will take mounting pressure on the folk at Apple to find ways to give permissions to web apps while protecting the privacy and security of users, which is what they pride themselves on.</p><p>App reviews by Apple (and whatever reviews Google carries out) are a good thing for users. A store with no reviews of quality or user protection could be detrimental.</p><p>However, if Apple is policing its store, who polices the police?</p><p>Apple breaks its own rules <a href="https://www.theverge.com/2019/2/18/18229492/apple-music-push-notifications-advertising">time</a> and <a href="https://www.theverge.com/2019/3/27/18284628/apple-news-plus-auto-subscription-breaking-rules-how-to-cancel">time again</a> to suit itself and <a href="https://www.theverge.com/2019/11/1/20943286/apple-tv-plus-free-trial-one-year-new-devices-cancel-auto-renew-how-to">manipulates</a> users into costly monthly subscriptions, something it prides itself upon for preventing third-party developers from doing.</p><p>Instead of stores limited to each operating system, we could see a platform-independent, global store of web apps. It could never be policed in the same way that Apple currently polices its store. But is Apple really doing a good enough job anyway?</p><p>This hypothetical store could allow apps to become “certified” so that users know such apps can be trusted. Along the lines of Twitter’s verified accounts.</p><p><em>This is still open to fraud, </em><a href="https://www.theguardian.com/politics/2019/nov/20/twitter-accuses-tories-of-misleading-public-in-factcheck-row"><em>as we saw from the UK’s Conservative party in 2019</em></a><em>, but if policed in the right way, and with users reporting misuse, app developers would be penalised accordingly for breaking the rules.</em></p><p>There will, of course, still be non-web apps, but they’ll become the minority, just as they are on desktop. For instance, there’s no desktop app for <em>YouTube</em> or for <em>Google Maps</em>, or for <em>Medium</em>, where I’m writing this article.</p><p>Instead, people are happy using the respective web apps. If such apps were to appear for desktop, it would make sense for them to be PWA versions of the existing websites that people are happy with.</p><p>The web will eventually rule on mobile, just as it does on desktop. It’s just a matter of time.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=92ee050bbaf1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/when-will-the-web-replace-native-mobile-apps-part-ii-92ee050bbaf1">When Will The Web Replace Native Mobile Apps? (Part II)</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[When Will The Web Replace Native Mobile Apps?]]></title>
            <link>https://medium.com/kinandcartacreated/when-will-the-web-replace-native-mobile-apps-5408c895c8a6?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/5408c895c8a6</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[progressive-web-app]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Wed, 24 Jun 2020 09:42:08 GMT</pubDate>
            <atom:updated>2020-06-24T12:49:55.955Z</atom:updated>
            <content:encoded><![CDATA[<h3>When Will The Web Replace Native Mobile Apps? (Part I)</h3><h4>What does the future have in store for mobile app development?</h4><p>With iOS developers everywhere getting excited by the latest WWDC announcements, it’s as good a time as any to consider the future of the good old native mobile app.</p><p>Steve Jobs, at the 2007 launch of the iPhone, <a href="https://youtu.be/ubm2dYzoDW8?t=4510">announced</a> that there would be “no SDK required” to bring apps to the iPhone. He continued:</p><p><em>“If you know how to write apps using the most modern web standards, [you can] write </em><strong>amazing</strong><em> apps for the iPhone today.”</em></p><p>A few moments later, Scott Forstall <a href="https://youtu.be/ubm2dYzoDW8?t=4606">began</a>:</p><p><em>“Not only am I going to show you how you can build great applications for iPhone using web technologies, but also how your applications running on the iPhone can take advantage of all the built in native services as well.”</em></p><p>Highlights of iPhone app development were displayed as:</p><ul><li>Web 2.0 and AJAX</li><li>Integrate with iPhone services</li><li>Instant distribution</li><li>Easy to update</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/719/1*NjTQ4lID_bcrrSC2IgkXog@2x.jpeg" /></figure><p>So where did it all go wrong? Will Apple’s original vision for iPhone apps one day become a reality?</p><blockquote>“Write amazing apps for the iPhone, using modern web standards.” — Steve Jobs, 2007</blockquote><p>Fast forward 13 years and it seems Apple is actively trying to stunt the progress of web capabilities on iOS.</p><p>However, with a global recession causing budget constraints like never before, will businesses still consider it necessary to offer a mobile app when a mobile-optimised website would suffice?</p><p>Advancements of web technologies and increased capabilities of progressive web apps (PWAs) are making mobile web a feasible replacement for apps.</p><p>But before considering an alternative to apps, it’s useful to contemplate why Apple’s original vision was not realised.</p><h3>Why apps in the first place?</h3><p>What changed since Jobs’ 2007 announcement? Why are we so content with websites on desktop, yet prefer to break out of the browser on mobile?</p><p>From the developer’s perspective, it might seem nonsensical at first. If we encouraged users to visit our mobile-optimised website, they wouldn’t have to spend time downloading software and we wouldn’t have to force them to update when we have new features or fixes to roll out. But instead, we constantly push them to our mobile app, even if they don’t yet have it installed.</p><p>But that’s an important point — installation. It’s not nonsensical for the developer, because once the user has downloaded and installed your app, they’re invested. That user has shown their loyalty and now you must repay them with a superior user experience.</p><p>So what about for the user? It only makes sense to download an app if the user believes they’ll be rewarded with a better user experience than that of the mobile website.</p><p>It ultimately boils down to user experience. Users don’t want apps. They want to get a job done: check the weather; pay a friend for lunch; rent a car; order a taxi.</p><blockquote>Users don’t want apps. They want to get a job done: check the weather; pay a friend for lunch; rent a car; order a taxi.</blockquote><h4>Why are apps not as popular on desktop?</h4><p>If apps enable users to achieve their outcomes more effectively than a website, why don’t we encourage users to use apps on desktop like we do on mobile?</p><p><strong>1 — For historical reasons</strong></p><p>Apps had to exist because mobile web offered a far inferior user experience than desktop web. When smartphones surfaced at the end of the Noughties, responsive web design was in its infancy and very few websites were mobile-optimised. Mobile data speeds were slow and heavy sites designed for desktop took a long time to load.</p><p>In October 2007, four months after the initial iPhone launch, Jobs announced that an iPhone SDK would be provided the following spring. Native apps would offer an experience that web apps would not be able to compete with, and, once downloaded, they would launch in an instant. Mobile web had a lot of catching up to do.</p><p><strong>2 — Serving different needs</strong></p><p>It’s also in part due to differences in how we use mobile compared to desktop. A mobile device has an abundance of hardware features to make it the useful device it is: accelerometer; camera; GPS; microphone; biometrics; NFC; Bluetooth; etc. Websites were historically unable to make use of such components, meaning apps were a necessity in order to make the most of the handset.</p><p>There are also operating system features that an app can access, such as contact information, calendar events, message composing and voice assistants. Many of these features are unavailable from mobile websites.</p><h3>That was then, this is now</h3><p>Mobile apps had to exist because smartphone technology out-paced mobile web technology.</p><p>Mobile serves a different purpose to desktop, and the amount that a developer was able to do within website code was insufficient to the needs of mobile users.</p><p>So does the continued evolution of progressive web apps change things?</p><p>PWAs aren’t new. The phrase was coined in 2015 and Google has promoted PWA development for Android since then. PWAs have been somewhat supported by iOS since 2017.</p><p>PWAs are also heavily endorsed by Microsoft for Windows 10, which runs on several mobile device families, such as Microsoft’s own Surface and PC market-leader Lenovo’s ThinkPad.</p><p>PWAs are also supported by desktop PCs and Google recently added support to <a href="https://9to5google.com/2020/05/28/google-chrome-progressive-web-app-pwa-startup/">Chrome to allow PWAs to be launched when your computer starts up</a>.</p><h3>PWA capabilities per platform</h3><p>A PWA’s power — and therefore its ability to compete with a native mobile app — is dependent on device manufacturer and operating system version (and also browser, but it’s not so relevant).</p><p>(This is just a summary, as there are lots of resources already available that go into great depth.)</p><h4><strong>Android</strong></h4><p>Some PWAs on a modern Android phone will be on par with a native Android app. Many of the aforementioned hardware components can be accessed from mobile websites, such as the accelerometer, camera and Bluetooth. PWAs load fast and can cache content for offline use, and there is support for push notifications to keep users engaged.</p><p>An app can be “installed” either through the Google Play Store or by adding to the home screen upon visiting the site in the mobile browser. Installing a web app actually generates an APK (Android Package Kit) in the background, which makes it equivalent to any other installed app (although it is still limited to the capabilities of the browser).</p><p>Android is leading the pack when it comes to supporting PWAs as “first class citizens” on a user’s device and we can expect continued evolution that sees the gap narrow between web apps and native apps.</p><h4><strong>Windows 10</strong></h4><p>The fact that Microsoft is promoting PWA development is important. Windows has almost 80% market share of desktop PCs, which increasingly double-up as mobile devices. Models such as the Surface Pro and ThinkPad have the benefit of many of those hardware components that define a mobile device. Depending on the type of app, e.g. a work-related productivity app, there could be a good business case to support Windows 10 via a PWA.</p><p>Microsoft has taken a step to simplify app discovery/distribution by <a href="https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-edgehtml/microsoft-store#automatic-pwa-importing-with-bing">automatically importing web apps to the Microsoft Store</a> when they are indexed by the Bing web crawler. The reason Microsoft is eager to support PWAs to their full extent is because fewer developers build native apps for Windows.</p><p>I’m not suggesting that Windows will be a competitor for Android or iOS any time soon. (<em>Windows Phone 7</em>, anyone?) But being promoted by Microsoft means we’re sure to see continued, rapid evolution of PWA development.</p><h4><strong>iOS</strong></h4><p>And finally, iOS. Despite Steve Jobs’ original vision for iPhone apps to be developed in “modern web technologies,” Apple now seems reluctant to support progressive web apps to the same extent as Google and Microsoft.</p><p>Despite broadcasting to the world that web apps would “integrate with native services,” iOS prevents web apps from interfacing with most of the hardware and operating system. Push notifications are also not supported — they have historically been tightly controlled by Apple even for App Store apps, so whether they will ever be allowed for web apps is unknown.</p><p>iOS support for PWAs is limited: web apps can take advantage of caching in order to load faster and store limited data for offline use; and the ability to “install” to the home screen means that a web app is given its own app-like housing, free of Safari. This means it is shown full screen, without the address bar and browser controls, and appears separately in the app switcher.</p><p>Steve Jobs cited the benefits of web-based apps as “instant distribution” and “easy to update.” However, Apple is now infamously precious about the kind of apps that may be distributed through the App Store. Unlike Google and Microsoft, it’s hard to imagine Apple ever allowing unvetted web apps into the store — and they can never be vetted, because web apps are dynamic; they could be changed entirely after review.</p><h3>So where to from here?</h3><p>Giving an existing website the capabilities that make it fall into the “progressive web app” category isn’t trivial, but it’s not nearly as costly as developing separate iOS and Android apps — or even Windows apps.</p><p>The user can still “install” the app, and even just having the app on their home screen ties them in with some level of commitment.</p><p>For many use cases the user experience can be pretty close in comparison to a mobile app, but there are also many use cases for which PWAs aren’t suitable, especially if targeting iOS is important.</p><p>I’m a native iOS developer, so I should be advocating native development — and I still do, for now — but I also think web advancements will make native development less and less necessary over time.</p><p>Of course there will still be professional productivity software that will always be better as native apps, in order to take better advantage of the device’s performance. For example, professional video or music editing, 3D modelling or graphic design products.</p><p>However, for businesses providing a service, such as retail, banking, transport and energy, which currently maintain a website as well as a mobile app, the need for a non-web app is guaranteed to reduce as web technology advances.</p><p>In <a href="https://medium.com/p/92ee050bbaf1">Part II</a>, I’ll go into the limitations of PWAs that are preventing me from advocating them over native apps, for now. I’ll also predict innovations we’ll see in the next few years that could make Apple’s original vision a reality — as much as they might now oppose that.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5408c895c8a6" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/when-will-the-web-replace-native-mobile-apps-5408c895c8a6">When Will The Web Replace Native Mobile Apps?</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iOS Pro: Pull-to-Search]]></title>
            <link>https://medium.com/kinandcartacreated/ios-pro-pull-to-search-74be33b76da?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/74be33b76da</guid>
            <category><![CDATA[iphone]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Thu, 17 Oct 2019 15:47:10 GMT</pubDate>
            <atom:updated>2019-10-19T09:11:36.459Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Sketch showing how pull-to-search works." src="https://cdn-images-1.medium.com/max/896/1*cMcy2eNBQRAkDZvu3T4nDA.png" /><figcaption>Pull-to-Search: a proposal for iOS</figcaption></figure><h3>Motivation for this series</h3><p><a href="https://edit.theappbusiness.com/ios-pro-getting-to-grips-with-one-hand-f375a3f40a8d">Apple has done a lot recently to make the iPhone easier to use one-handed.</a> However, since upgrading to the iPhone 11 Pro, I have been disappointed by the lack of 3D Touch text editing. They promote all the things they do to make one-handed use easier, but never mention the fact that they’ve removed what I consider one of the real “pro” features of iOS. With the lack of 3D Touch, I want to explore further lengths Apple could go to, to improve the one-handed experience.</p><h3>Inspiration for this article</h3><p>The pull-to-search feature of the iOS home screen is great. I use it all the time. I have so many apps cluttering several pages of my home screen that the easiest way to open an app is to “pull down” on the home screen and start typing (or tapping a Siri suggestion). I feel this pull-to-search feature could be rolled out across the system and in third-party apps, as a “pro” feature.</p><h3>What is pull-to-search?</h3><p>When you pull down on the home screen of iOS, the search bar appears and immediately has focus. The keyboard appears at the same time and you can start typing quickly to find whatever you’re looking for on your device.</p><p>Within apps the search bar always appears at the top of the screen and forces the user to reach awkwardly to initiate a search and reveal the keyboard. (An exception to this is Apple’s <em>Maps</em> app, which makes the search field much more reachable at the top of a sliding “card” style modal.)</p><p>I envision the same pull-to-search functionality from the home screen could be used in apps. The user would pull down on the content beneath the search field and pulling beyond some threshold would trigger the search field to become focused.</p><blockquote>This feature would compete with pull-to-refresh. You couldn’t have both. However, given the fact that <a href="https://www.fastcompany.com/3023421/why-the-pull-to-refresh-gesture-must-die">even the inventor of pull-to-refresh wants his own idea to die</a>, I think we can all feel comfortable with a more useful feature replacing it. (Live content should be updated automatically without having to pull!)</blockquote><p>Take the iOS <em>Phone</em> app. The Contacts tab has a search feature, but when using my phone one-handed, I’m reluctant to use it. It forces me to reach awkwardly to the top of the screen to begin typing. Wouldn’t it feel “pro” if you could just swipe down to begin searching? I’ve imagined it working like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*kTA6wi5RUWSQuGlPxvpm7Q.gif" /></figure><p>As the user drags the table down beyond an initial threshold, I begin drawing a border around the edge of the text field to indicate that something is happening. Dragging beyond another threshold—indicated by the border joining up—triggers the search field to become focused.</p><p>With a quick and intentional swipe down, the user wouldn’t necessarily see the border being drawn, but with a slower scroll, the border would highlight to the user that continuing past the threshold will initiate the search.</p><p>Once the search field is focused, tapping anywhere outside of it dismisses the search controller (this comes for free). With these interactions, my thumb doesn’t need to leave the bottom portion of the screen to begin or cancel searching.</p><h3>Clash with pull-to-dismiss</h3><p>Pull-to-dismiss is a new feature of iOS 13 that allows the user to pull a modally presented view down to dismiss it (a.k.a. swipe to dismiss). This would clash with pull-to-search.</p><p>I’ve <a href="https://twitter.com/dodsios/status/1184835119158382597">witnessed</a> Apple prioritising a completely pointless pull-to-refresh over the intuitive and practical pull-to-dismiss (iOS App Store app, Account screen). It’s a shame when iOS introduces a great feature like this but fails to adopt it consistently.</p><p>The solution I propose means that pull-to-search and pull-to-dismiss can coexist harmoniously.</p><p>Apple has given developers the ability to detect when pulling to dismiss, in order for us to perform some other action instead. For instance, in the case of adding a Calendar event, pulling down could either (a) cancel and discard changes or (b) save changes. In this case, when the user pulls down to dismiss the Add Event view, the view is not dismissed and instead the app shows an action sheet for possible actions. (Apple has apparently decided not to give the complete set of actions which would have included the Add (Save) action.)</p><figure><img alt="Screenshot of iOS Calendar app, New Event screen. Showing action sheet to avoid ambiguity over dismiss action." src="https://cdn-images-1.medium.com/max/1000/1*IQ7uhuhxQjIj9N1bApgz8Q@2x.jpeg" /><figcaption>Pull-to-dismiss in the iOS Calendar app, New Event screen. Showing action sheet to avoid ambiguity.</figcaption></figure><p>I envision this could be extended in the case that a search field is present at the top of the modal. For example, the Add Invitees modal in the Calendar app has a search field as well as two distinct navigation bar buttons (Cancel on the left; Done on the right). Pulling down to dismiss could trigger an action sheet to give the user complete control without having to reach their thumb uncomfortably.</p><figure><img alt="Animation showing proposal for pulling to dismiss and seeing the option to begin a search." src="https://cdn-images-1.medium.com/max/320/1*gNKUg55Ess-tRIvzTN82OA.gif" /><figcaption>Pull to perform action!</figcaption></figure><h3>Pull to perform action</h3><p>The animation above shows what is essentially a “pull to perform action” feature. The set of actions available depends on the context.</p><p>With this in mind, we could provide this user experience regardless of whether we have a search field.</p><p>Implementing this is fairly straightforward:</p><ol><li>Set isModalInPresentation = true for the modally presented view controller.</li><li>Set the relevant presentation controller’s delegate and implement the presentationControllerDidAttemptToDismiss method of UIAdaptivePresentationControllerDelegate.</li><li>In the delegate method, instantiate and present a UIAlertController with style .actionSheet.</li></ol><p>The code looks like this as a starting point:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/03a8b647a9d40ceda0b6310adcdb40b0/href">https://medium.com/media/03a8b647a9d40ceda0b6310adcdb40b0/href</a></iframe><h3>“Hold up! This is just weird and unintuitive!”</h3><p>Don’t forget pull-to-refresh is a hidden and unintuitive feature too! In fact, if you think my proposed feature is bad, you must think pull-to-refresh is much worse because it’s often the <em>only</em> way to refresh, which is a major Accessibility fail!</p><p>I’m not proposing pull-to-search is the only way to initiate a search. No way! Of course you can still interact with the search field. Just like you can still explicitly tap the Cancel or Done buttons in the navigation bar. I’m just proposing that “pulling down” on the content seems like a sensible way to trigger functionality without having to extend your thumb awkwardly and risk dropping your phone.</p><p>My proposed feature is “discoverable” just like pull-to-refresh. But when a feature like this becomes commonplace, users expect it. Users will soon become familiar with pull-to-dismiss and the “pull to perform (otherwise ambiguous) action” functionality provided in Apple’s apps. Pull-to-search is just an extension of that.</p><p>Many users may never discover it, which is what makes it a “pro” feature!</p><h3>That’s it!</h3><p>Although you could take it further still! Imagine a page of a form that has several text fields, the first of which is at the top of the screen. In order to begin filling out the form, the user must reach to the top of the screen to interact with the first text field. You could extend my proposed pull-to-search feature to “pull-to-begin”.</p><p>Now that would feel really pro!</p><p>Follow me on <a href="https://twitter.com/dodsios">Twitter</a> for random updates, or just say hi. 👋</p><p>TAB is hiring! iOS engineers of all levels in London and <a href="https://www.linkedin.com/pulse/im-here-were-sam-dods/"><strong>now in Edinburgh</strong></a>! Head over to <a href="https://theappbusiness.com/careers">theappbusiness.com/careers</a> for more info!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=74be33b76da" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/ios-pro-pull-to-search-74be33b76da">iOS Pro: Pull-to-Search</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iOS Pro: Getting to Grips with One Hand]]></title>
            <link>https://medium.com/kinandcartacreated/ios-pro-getting-to-grips-with-one-hand-f375a3f40a8d?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/f375a3f40a8d</guid>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[iphone]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Tue, 15 Oct 2019 17:01:23 GMT</pubDate>
            <atom:updated>2019-10-16T08:56:43.284Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Photo showing a thumb reaching to the top of the screen awkwardly" src="https://cdn-images-1.medium.com/max/1024/1*g1f7NvgeTrFj4IotKeGRcg.jpeg" /><figcaption>As phones get bigger, the navigation bar gets further out of reach</figcaption></figure><p>The birth of the iPhone 11 Pro marks the death of one of the iPhone’s most pro features: <em>3D Touch text editing</em>.</p><p>Although it’s devastating to see this incredible feature disappear, it’s interesting to see Apple introducing new ways to make it easier to use your iPhone with only one hand. I’m going to look at some of the iOS features that still make me feel like a pro now I can no longer use 3D Touch.</p><h3>Why one-handed use is so important</h3><p>I imagine anyone fortunate enough to have two hands regularly uses only one of them to hold their phone. You often have something better to do with your free hand. Whether holding an umbrella, a coffee, a baby or—in the case of a true pro—a briefcase, you do most of your typing, swiping and liking using a single thumb.</p><p>When you’re using only one hand, it’s difficult to reach the top of the screen to engage things like a search bar, a back button or other navigation bar buttons. Without the support of a second hand, you risk dropping your device. And since the cost of your device is greater than the deposit my parents paid on our first family home, it would be a costly drop!</p><p>With phones getting bigger, it’s getting harder to reach into the top corners without using another hand. However, there are improvements we can make as developers to improve user experience with one hand. In this article I’ll explore some improvements Apple has made.</p><h3>Native iOS features to improve one-handed use</h3><h4>1. Pull-to-dismiss on iOS 13</h4><p>The newest one-handed improvement is in the way iOS 13 modals can be dismissed by swiping down with one finger (or for most people, one thumb). Modals in iOS 13 by default do not fill the entire screen. Instead they act like a “card” which appears in front of the presenting view, leaving a gap at the top of the screen where the very top of the underlying view is still visible. If the presented content’s scroll position is at the top (beginning of the content) then swiping down anywhere will dismiss the view.</p><blockquote>What’s really cool is that developers can opt out of pull-to-dismiss when there are multiple options or if the dismiss action is ambiguous. Instead we can display an action sheet of options to give the user complete control.</blockquote><figure><img alt="Screenshot of iOS Calendar app, New Event screen. Showing action sheet to avoid ambiguity when pull-to-dismiss is invoked." src="https://cdn-images-1.medium.com/max/1000/1*HkHsGVbx-Gm3hGZiQ1KCPQ@2x.jpeg" /><figcaption>Pull-to-dismiss in the iOS Calendar app, New Event screen. Showing action sheet to avoid ambiguity.</figcaption></figure><p>This is a one-handed improvement because it means you don’t have to reach for the Done or Cancel button at the top of the screen. (It would be nice if Apple had also added a “Save” option to the action sheet!)</p><p>Swipe-to-dismiss has been common in third-party apps for a while. Lots of apps support a swipe gesture to dismiss photos. It’s even seen in Apple’s own apps such as Music, to dismiss the <em>Now playing</em> view. However, with iOS 13 this behaviour comes as default for third-party developers. Result!</p><p>(Developers: implement <a href="https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/3229888-presentationcontrollerdidattempt">presentationControllerDidAttemptToDismiss</a> to detect dismissal and present an action sheet.)</p><h4>2. Swipe to go back</h4><p>The Back button has always lived in the top-left of the navigation bar. Since iOS 7, users have been able to swipe from the left edge of the screen to go back. This gesture is the same action as pressing Back but doesn’t require our coffee-slurping, briefcase-waving pros to reach their tired (right?) thumb to the top (left!) of the screen.</p><p>Some app developers implement their own Back buttons or hide the navigation bar altogether and fail to realise that they can still leverage the native swipe-to-go-back functionality <a href="https://stackoverflow.com/a/19834167/845027">by adding a single line of code to their view controller</a>. Please do it!</p><blockquote>It’s interesting to note that in the iOS App Store app, if you’ve opened an article from the Today tab, you can swipe from the left edge of the screen to close it. This is despite it having been presented modally rather than pushed onto a navigation stack! Pull-to-dismiss AND swipe-from-left-edge are BOTH supported.</blockquote><h4>3. Pull-to-search from home screen</h4><p>Swipe down anywhere on the iOS home screen and the search bar will be revealed along with the keyboard so you can immediately start typing. The introduction of this feature meant that no longer did you have to swipe past the first page of your home screen content to reach the search function.</p><p>Swiping past the first page is still an option and it reveals your widgets along with the search bar at the top. However, to engage with the search bar from there, you need to awkwardly reach to the top of the screen. Pull-to-search is a one-handed shortcut for the pros amongst you.</p><h4>4. One-handed keyboard</h4><p>This is, I suppose, the most obvious advancement. The clue is in the name. Apple is explicit in its intended use of this feature. I don’t personally see much value in it, but I’m on a standard model, rather than a Max model. Maybe this is useful for iPhone Max (or formerly, Plus) users.</p><figure><img alt="Screenshot showing the one-handed keyboard on iOS." src="https://cdn-images-1.medium.com/max/1000/1*t9m1hAUwQTlEMqg-zgJyGg@2x.jpeg" /><figcaption>The right-handed one-handed keyboard option on iOS</figcaption></figure><h4>5. iOS keyboard as a trackpad</h4><p>You can use the native keyboard as a kind of trackpad. On a device with 3D Touch you can force-press anywhere on the keyboard to enter trackpad mode. Then drag your finger to move the cursor within the text view or text field. Force-press again while dragging and you’ll select the word under the cursor. Force-press again and your selection will increase to the paragraph. Force-press again to cancel selection and again to re-cycle through the selection options.</p><p>Text selection like this felt like a real one-handed pro feature. Sadly it’s no longer available on the iPhone 11 Pro and Pro Max. But you can still turn the keyboard into a simple trackpad by long-pressing the spacebar. Not quite as pro, but still allows for basic cursor control without your one thumb having to leave the bottom portion of the screen.</p><figure><img alt="Screenshot of iPhone, showing keyboard as trackpad, following a long-press on the spacebar." src="https://cdn-images-1.medium.com/max/993/1*Fj793j0ZOA2AsamObpb4ug@2x.jpeg" /><figcaption>Long-press the spacebar to turn the keyboard into a trackpad</figcaption></figure><h3>Bottom third</h3><p>This is where it’s at, yo! Your thumb is comfortable at the bottom of the screen. The keyboard’s accessory view is as high up the screen as I would ever really want to reach with my thumb.</p><h3>What you can do as a developer</h3><p>Ensure you don’t override native functionality. For example, if you have implemented your own Back button or collapsed the navigation bar, ensure you still <a href="https://stackoverflow.com/a/19834167/845027">support swipe to go back</a>. If you display a modal, consider keeping the iOS 13 native pull-to-dismiss functionality (it comes for free, so no excuses) and consider showing an action sheet to avoid ambiguity over the action taken upon dismissal.</p><p>I think modals that don’t support pull-to-dismiss are quickly going to feel out of place, or even buggy. Just like when the swipe-to-go-back feature doesn’t work.</p><p>Another simple way you can help is to ensure you add Next/Previous/Go buttons to the keyboard’s accessory view, so you can easily navigate between form fields. And ensure you hook up the keyboard’s Return key to act as a Next or Submit (Go) button.</p><p>Aim to limit the need for a user to reach to the navigation bar. The below images are some examples in iOS stock apps where the experience is negatively impacted by having to reach to the navigation bar to back-out of a view.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wxkLyYti_7nwRAuy1lgTBg.png" /><figcaption>Cancelling search anywhere is hard; dismissing an attachment; pull-to-refresh conflicting with dismiss.</figcaption></figure><h3>The unmentionables</h3><p>Apple has a habit of shouting about the enhancements to usability without mentioning their own degradations. (<a href="https://brettterpstra.com/2015/10/19/a-magic-mistake/">Rearrangement</a> <a href="https://news.ycombinator.com/item?id=17901776">of</a> <a href="https://sixcolors.com/post/2015/10/apple-magic-keyboard-review/">the</a> <a href="http://morrick.me/archives/7451">cursor</a> <a href="https://www.macworld.com/article/2995375/apple-magic-keyboard-review-should-have-called-it-basic.html">keys</a> on MacBook, anyone?)</p><p>1. The fact that I need to reach to the top of the screen to initiate Control Center, I get, but I don’t like. I’m not going to risk that with one hand while my shiny new phone is still new and shiny.</p><p>2. I’d say the top three rows of apps on my home screen are pretty much unreachable with one hand without risking dropping and damaging this costly device. Subsequently I position my most-used apps along the bottom few rows, with my most-used apps either in the dock or on the bottom row. I have apps I’ve never used sitting along the top rows just to push the ones I do use into a reachable position. I’d love Apple to allow me to position apps anywhere on the screen, rather than enforcing this top-left-to-bottom-right layout.</p><p>3. A feature of iOS I’m not a fan of is Reachability. On an iPhone X or later, this is initiated by swiping down from the bottom of the screen. It results in the top half of the screen moving to the bottom so you can more easily reach elements at the top of screen. However, in doing so, the bottom half completely disappears. I think this is an admission of guilt that there may be content out of reach that is worth interacting with. I have disabled this feature on my device because I’ve only ever initiated it accidentally, which is just annoying.</p><p>There are improvements that could help make this content more reachable without the Reachability solution/afterthought/hack.</p><h3>Look out!</h3><p>I’m going to explore and propose some improvements in my following articles, so watch this space if you’re a fan of the pro one-handed user experience.</p><p>Follow me on <a href="https://twitter.com/dodsios">Twitter</a> for updates, or just say hi. 👋</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f375a3f40a8d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/ios-pro-getting-to-grips-with-one-hand-f375a3f40a8d">iOS Pro: Getting to Grips with One Hand</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making UILabel Accessible]]></title>
            <link>https://medium.com/kinandcartacreated/making-uilabel-accessible-5f3d5c342df4?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/5f3d5c342df4</guid>
            <category><![CDATA[accessibility]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Wed, 09 Oct 2019 10:41:44 GMT</pubDate>
            <atom:updated>2019-10-09T10:48:53.702Z</atom:updated>
            <content:encoded><![CDATA[<p>When it comes to arguing the benefits of a mobile app vs. a mobile website, it’s pretty easy to sell the advantages of the former, <em>in my opinion!</em></p><p>However, one major advantage mobile web has over an app is that all text on a web page is selectable. That’s not the case for a mobile app.</p><p>UITextView supports selection through its isSelectable property, whereas UILabel does not. This can make for an annoying user experience when a user wants to copy some text from your app.</p><p>What’s worse is that without text selection, you cannot support the native accessibility feature <em>Speak Selection</em>.</p><h3>Speak Selection</h3><p>This is an accessibility feature enabled in <strong>iOS Settings app &gt; Accessibility &gt; Spoken Content &gt; Speak Selection</strong> (switch on/off).</p><p>If Speak Selection is turned on, when text is selected, the usual menu that appears to show contextual actions, such as Copy and Paste, also includes the Speak option.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RmWhfJN5IABizMzoxaUxVg.png" /><figcaption>Long press to bring up the contextual menu where you’ll find the “Speak” option</figcaption></figure><p>As an app developer, you get this for free when using a `UITextView` to display text.</p><p>However, because UILabel doesn’t support text selection, you need to implement custom logic to present this menu and support text-to-speech.</p><h3>Copy text</h3><p>Accessibility doesn’t just refer to improving the experience for users with disabilities. We shouldn’t just think about text selection for <em>speaking</em> as an improvement in accessibility. Allowing text selection for the purpose of <em>copying</em> is an improvement in accessibility too. Giving users the <em>ability</em> to copy product names, ingredients, contact details, prices and other text improves the all-round experience.</p><p>Being able to <em>copy</em> text means your users can then <em>paste</em> text into, say, a text message or a language translation tool. It may be harder for some users to remember even short pieces of text, so being able to copy and paste is really important.</p><p>Because both require text selection, it makes sense to support Speak and Copy at the same time.</p><h3>Selecting text in a UILabel</h3><p>Because a UILabel generally holds short pieces of text, it seems acceptable to select the content in its entirety, rather than allow selection of individual words like UITextView does.</p><p>The steps are as follows:</p><ol><li>Create a subclass of UILabel which you will use anywhere you want your label text to be selectable.</li><li>Add a long press gesture recogniser.</li><li>Upon long press, present the UIMenuController shared instance with the menu items you need, in this case, <strong>Copy</strong> and <strong>Speak</strong>. (You might choose only to add the Speak option if UIAccessibility.isSpeakSelectionEnabled == true, but there’s no harm in always giving the users this option!)</li><li>Implement methods for copying and speaking, which are called when your menu items are tapped.</li><li>Optionally, I suggest highlighting your text with a dark overlay to indicate what is selected. UIMenuController posts a notification when it hides, so you can observe that and dismiss your overlay.</li></ol><p>Pretty straightforward, right? Let’s see what the code looks like…</p><h3>SelectableLabel</h3><p>The below is a snippet showing the important functionality:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/de016eff46dec209e787fca9b4beab4c/href">https://medium.com/media/de016eff46dec209e787fca9b4beab4c/href</a></iframe><p>Breaking this down, we have:</p><ol><li>Initialisation and setup. Adding the overlay view, which will be shown/hidden when focus is given to the label. Adding the long press gesture recogniser. Observing the UIMenuController.didHideMenuNotification notification in order to hide our overlay.</li><li>Hide the overlay when the menu hides.</li><li>Responding to the long press gesture. Make the label first responder. This is so we can hide the overlay when the label resigns first responder. Create the menu and set its target rect. Setup the menu items with Copy and Speak options, then show the menu.</li><li>Responding to user selecting the Copy and Speak options. Copy is simple, just copy the string to the clipboard (UIPasteboard.general). Speak is slightly more involved. Specifying .duckOthers means that any other audio such as music will be reduced in volume to allow the spoken text to be heard.</li><li>Create a speech synthesizer. If it’s already speaking, then stop at the next word boundary, using .word option. Set the “utterance” to the label’s text and then speak it out loud.</li></ol><h3>Speech Synthesizer shared instance</h3><p>The speech synthesizer is implemented like so:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4deec844266f7191155883e0f36608ed/href">https://medium.com/media/4deec844266f7191155883e0f36608ed/href</a></iframe><p>The purpose of this speech synthesizer extension is to provide a shared instance that has a delegate. The delegate is a shared instance of private class SpeechDelegate, which is responsible for deactivating the audio session once the utterance has finished.</p><h3>The result</h3><p>We now have a label that we can use anywhere in the app, in place of a UILabel. When long pressed, a menu is presented like so:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/782/1*vk87_6nbEQp5cSSaRBmVTQ.png" /><figcaption>Long press the label to reveal the contextual menu</figcaption></figure><p>The complete code for this is on <a href="https://github.com/samdods/SpeakSelection">GitHub</a>.</p><p>This improves the user experience for everyone, not just those with specific accessibility needs. I really recommend adding Copy and Speak to the labels in your own apps. Perhaps it’s not necessary to add it to every label, but I don’t see any harm.</p><p>Any questions, give me a shout on <a href="https://twitter.com/dodsios">Twitter</a>. 👋</p><p>If you want to join me and the TAB team in our quest to make better user experiences for everyone, <a href="https://www.theappbusiness.com/careers">check out our roles and benefits</a> and please <a href="mailto:opportunities@theappbusiness.com">get in touch</a>.</p><p>Now hiring in <a href="https://www.theappbusiness.com/careers/senior-ios-engineer-edinburgh">Edinburgh</a>! 🏴󠁧󠁢󠁳󠁣󠁴󠁿🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5f3d5c342df4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/making-uilabel-accessible-5f3d5c342df4">Making UILabel Accessible</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Inner Workings of Server-side Swift]]></title>
            <link>https://medium.com/kinandcartacreated/the-inner-workings-of-server-side-swift-177b2fcce86c?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/177b2fcce86c</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[server-side-swift]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Wed, 10 Apr 2019 11:59:13 GMT</pubDate>
            <atom:updated>2019-04-11T07:31:35.512Z</atom:updated>
            <content:encoded><![CDATA[<p>Very few developers, perhaps least of all iOS developers, need to write low-level networking code. We rely on native frameworks built into our target platform, such as (NS)URLSession for iOS development, and often third-party frameworks for a higher level of abstraction.</p><p>So, as an iOS developer myself, why did I bother trying to understand C-level networking APIs in order to write my own Swift server? The answer is simple: for fun, of course! 🤓</p><p>An example of when an iOS developer might use Swift to build a server is for building a mock backend for UI testing.</p><h3>Swift on the server</h3><p>With the news that <a href="https://www.theregister.co.uk/2015/06/08/apple_open_source_swift/">Swift was going to be open sourced and able to run on other platforms beside Apple’s</a>, so came along many server-side Swift frameworks, such as <a href="https://perfect.org">Perfect</a>, <a href="https://www.kitura.io">Kitura</a>, <a href="https://vapor.codes">Vapor</a> and <a href="https://github.com/amzn/smoke-framework">Smoke</a>.</p><p>While it’s great that there are so many options, I always like to have a basic understanding of what’s going on under the hood when I use a third-party framework. So I got digging.</p><p>What I arrived at was <a href="https://github.com/samdods/Frank">Frank</a>, a proof of concept, standalone Swift server (very!) loosely based on Ruby’s <a href="http://sinatrarb.com">Sinatra</a> framework. I’ve described below the journey I went on to build it.</p><h3>Consuming remote content</h3><p>Server-side code exists so that it may be consumed by clients such as apps and web browsers. There wouldn’t be much point in a server without a client, so this is where I started.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uDSmjFTnNFGOX9yYldFcTw.png" /><figcaption>Consuming remote content</figcaption></figure><p>The client application needs to consume remote content, such as <strong>JSON</strong>, <strong>HTML</strong>, <strong>Images</strong>, or perhaps just <strong>mock data</strong>. I mention mock data, because the only Swift servers I’ve ever actually built are for just that. I see Swift as a great language to use for mock servers, because it means the app code and the mock server code are written in the same language.</p><p>So how does an iOS app consume remote content? What is that magic?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RfJ7u1ezVNm1Ao8_XaBr2A.png" /><figcaption>The flow of communication between a client app and a remote service</figcaption></figure><ul><li>Your app code will likely interface with URLSession directly, or indirectly via a third-party framework. (There are a bunch of options: <a href="https://github.com/Alamofire/Alamofire">Alamofire</a>, <a href="https://github.com/theappbusiness/TABResourceLoader">TABResourceLoader</a>, <a href="https://github.com/BottleRocketStudios/iOS-Hyperspace">Hyperspace</a>, <a href="https://github.com/bustoutsolutions/siesta">Siesta</a>.)</li><li>URLSession uses C-level APIs to open a socket for communicating over the network.</li><li>The network may be within a single building, span a campus, or extend to every corner of the planet, but in essence it’s the same principle as if it was simulated on a single machine, as in my mock server example. (To connect to Medium, my laptop has communicated with my router, then my ISP, in order to setup the socket-to-socket connection.)</li><li>The server application uses its own C-level APIs to open its own socket and “bind” it to a port number in order to listen to incoming connections.</li></ul><p>The communication between the socket on the client and the socket on the remote is conducted using a collection of protocols. Operating systems use TCP/IP to specify how data is batched, transmitted, routed and received over the network (or internet). HTTP sits on top of this. Among other things, it specifies how the data is formatted so that the consuming application knows how to interpret it.</p><h3>Inspecting the HTTP messaging format</h3><h4>HTTP Request</h4><p>The request takes the following format:</p><pre>POST /account/update_password?trace_id=29acf01f100a HTTP/1.1<br>Host: 127.0.0.1:8080<br>Content-Type: application/json<br>User-Agent: curl/7.54.0<br>Accept: application/json<br>Authorization: ABE0FD5A3B2C2D4A56FE7B8B9A9CF6543B21AEE8FCA</pre><pre>{<br>    &quot;password&quot;: &quot;As if! 😂&quot;<br>}</pre><p>Let’s break this down:</p><ul><li>POST is the <a href="https://restfulapi.net/http-methods/">HTTP method</a>.</li><li>/profile/update?trace_id=29acf01f100a is the path component of the URL combined with any URL query parameter(s), which in this case is just a trace_id, but we could pass any key/value pairs here.</li><li>HTTP/1.1 is the protocol version number, so the recipient knows how to interpret the rest of the message.</li><li>Host: 127.0.0.1:8080 specifies the target machine and port number.</li><li>Then comes a series of Key: value pairs called headers. These are added by the client at different stages. For example, above I’ve specified values for <strong>Content-Type</strong>, <strong>Authorization</strong> and <strong>Accept</strong> keys. The curl command line application that I used to send the request has added a value for the <strong>User-Agent</strong> key. The key/values above are just examples. There may be any number of key/value pairs added to a real request.</li><li>A single empty line separates the headers from the body (if any; not all requests include a message body).</li><li>The body is everything below the empty line, until the <a href="https://en.wikipedia.org/wiki/End-of-file">EOF</a>. The header Content-Type: application/json<strong> </strong>tells the receiver to expect JSON in the body.</li></ul><h4>HTTP Response</h4><p>An HTTP response takes the following format:</p><pre>HTTP/1.1 400 Bad Request<br>Content-Type: application/json<br>Content-Length: 182</pre><pre>{<br>    &quot;error&quot;: {<br>        &quot;status&quot;: &quot;INVALID&quot;,<br>        &quot;message&quot;: &quot;The password provided contains invalid characters. You may only use letters, numbers and standard punctuation characters.&quot;<br>    }<br>}</pre><p>Breaking this down we have:</p><ul><li>HTTP/1.1 confirms the protocol version number.</li><li>400 Bad Request specifies the status code and the description of that status code. If this had been successful, we would have expected 200 OK.</li><li>Then there are a series of key/value pairs (headers), in this case <strong>Content-Type</strong> and <strong>Content-Length</strong>. The content length is important. It means the consuming application knows how much memory to allocate for the body of the message.</li><li>A single empty line separates the headers from the response body.</li><li>The body is everything below the empty line, until the <a href="https://en.wikipedia.org/wiki/End-of-file">EOF</a>.</li></ul><p>It’s the format of the HTTP response that is important for us to understand in order to build a server, because the server will be responding to client requests.</p><h3>Responding to HTTP requests</h3><p>Accepting and responding to HTTP requests is actually a fairly simple process. The hardest part is figuring out how to interact with the C APIs after they’ve been bridged to Swift. In the code that follows, the complex C-wrangling is hidden behind <a href="https://github.com/samdods/Frank/blob/frank/Frank/Private/Helpers.swift">these helper methods</a>.</p><p>The steps to run a server are as follows:</p><ol><li>Create a socket reference</li><li>Set socket options</li><li>Bind the socket to an IP address and port number</li><li>Listen on the socket</li><li>Wait for a request</li><li>Parse and route the request</li><li>Write the response (if any) to the socket</li><li>Close the request</li></ol><p>Steps 5–8 are repeated for the lifetime of the server application (i.e. it’s a loop that runs indefinitely until the application is terminated).</p><p>The following code sets up the socket and listens on it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fd4df69212b1fb21e16e2cf39ac8af6e/href">https://medium.com/media/fd4df69212b1fb21e16e2cf39ac8af6e/href</a></iframe><p>Then we need to loop indefinitely while we wait to accept and respond to requests.</p><p>It’s by no means trivial to read the contents of the HTTP request and it’s completely up to you how you build the response, depending on what it is that your server is meant to be doing. I’ve simplified this in the code below so as not to detract from the C-level API usage I’m trying to demonstrate. (I’m using my own Request type and additional methods I’ve written, routeRequest, handleError and httpResponse, which are explained later.)</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1d21e3f236b5ed8d47365a3e65971f68/href">https://medium.com/media/1d21e3f236b5ed8d47365a3e65971f68/href</a></iframe><p>As you can see from the code above, accepting the connection (step 5), writing the request (step 7) and closing the request (step 8) are pretty straightforward. It’s parsing and routing the request (step 6) which is the more difficult part.</p><p>The fd variable is a file descriptor. It’s just an integer that the lower-level functions use to reference the data received on the socket. It represents the connection to one specific client. (The sock variable is another file descriptor representing the socket itself.)</p><p>I’m passing the file descriptor into the initialiser for my Request type. <a href="https://github.com/samdods/Frank/blob/frank/Frank/Server/HTTP.swift">In the initialiser</a>, I read and parse the data to set httpMethod and path properties—assuming the data is in the HTTP format as expected.</p><p>The routeRequest method decides how the request should be processed by the server application, i.e. what is the request and how should we respond. Is it a request for profile information? Search results? Is it a friend request? Is it an update password request? This is where the server executes the business logic that the request is initiating. The server can optionally return a response body string to be sent back to the client that sent the request.</p><p>The handleError method transforms an error into a response body string and status code in order to be written to the response to the client.</p><p>The httpResponse method builds an HTTP-formatted response, given the body string and the status code.</p><p>And that’s pretty much it! Now we can use it…</p><h3>Serving content</h3><p>I said this server was <em>(very!) loosely based on Sinatra</em>, but Frank doesn’t look much like Sinatra yet, does it?</p><p>Sinatra endpoints (or routes) are defined, for example, like so:</p><pre>get &#39;/home&#39; do<br>    &quot;🏠&quot;<br>end</pre><p>So the final pieces of the puzzle are to wrap up all the server code above and put it in a static start method; provide the get method to offer similar syntax to Sinatra; and to define the routeRequest method that I mentioned above:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f73e4c02c386a87d3853cabb2223b657/href">https://medium.com/media/f73e4c02c386a87d3853cabb2223b657/href</a></iframe><p>Then I can define my endpoints and launch the server as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fdd59a8daca893fda3910f852627be4d/href">https://medium.com/media/fdd59a8daca893fda3910f852627be4d/href</a></iframe><p>Build and run in Xcode to advertise the server on the port specified. Or archive to a command line utility to run from the command line.</p><p>The full code is available here: <a href="https://github.com/samdods/Frank">https://github.com/samdods/Frank</a></p><h3>Where to go from here?</h3><p>Frank is not going anywhere. It’s a demo project and I’m obviously not going to compete with the server-side Swift heavyweights. But if I wanted to, I’d begin by adding support for:</p><ul><li>Dynamic paths, e.g. /profile/:id, where id is a variable I can use in the scope of handling the request.</li><li>Query parameters, e.g. /search?query=sausages, where the query parameters are available in the scope of handling the request.</li><li>All HTTP methods, POST, DELETE, HEAD, etc.</li><li>Command line arguments for things like port number and IP address.</li><li>Handling multiple requests at the same time. (Current solution is “blocking” the single thread while waiting for data to be received and processing each request.)</li><li>Running the server on Linux.</li></ul><p>In order to support Linux and macOS at the same time, I’d need to wrap a load of my code in compiler directives, like so:</p><pre>#if os(macOS)<br>    ... import Darwin, etc.<br>#elseif os(Linux) || os(FreeBSD) || os(Android)<br>    ... import Glibc perhaps, etc.<br>#else<br>    fatalError(&quot;Unsupported operating system&quot;)<br>#endif</pre><h3>What have I learnt from this?</h3><p>It wouldn’t be much use without some lessons to take away…</p><ul><li>Working with C APIs is a pain, especially if you need to support multiple operating systems. But it’s fun once you crack it!</li><li>Working with a higher-level framework is much nicer. Even <a href="https://github.com/apple/swift-nio">SwiftNIO</a> is a nice abstraction (Apple’s framework, which <a href="https://github.com/IBM-Swift/Kitura">Kitura</a> and <a href="https://github.com/amzn/smoke-framework">Smoke</a> both use under the hood).</li><li>Don’t attempt to bind an IPv4 address (AF_INET) to an IPv6 socket (AF_INET6). It won’t work! 🤬</li><li>Don’t use myString.count for string byte length! Use myString.utf8.count instead. 🤪</li></ul><h3>Conclusion</h3><p>It’s awesome that there are so many open source frameworks allowing us to write Swift code for server-side applications. However, like any third-party dependency, it’s nice to have a vague understanding of how they work internally. When choosing a framework, have a look at the selling points of each one and make your choice based on use case. And bear in mind, that if your requirement is basic, then you may not even need a dependency at all.</p><p>Unfortunately I can’t tell you which server-side Swift framework will come out on top, but I can tell you it won’t be <a href="https://github.com/samdods/Frank">Frank</a>. 😉</p><p>If you’re interested in how things work and you want to join a passionate team of Swift enthusiasts, head to our <a href="http://www.theappbusiness.com/join">careers page</a>!</p><p><a href="https://twitter.com/dodsios">Follow me on Twitter</a> for occasional mutterings.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=177b2fcce86c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/the-inner-workings-of-server-side-swift-177b2fcce86c">The Inner Workings of Server-side Swift</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Switching App Environment at Runtime—A Counterargument]]></title>
            <link>https://medium.com/kinandcartacreated/switching-app-environment-at-runtime-a-counterargument-3a798a421dcf?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/3a798a421dcf</guid>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Mon, 11 Mar 2019 11:13:10 GMT</pubDate>
            <atom:updated>2019-03-11T11:13:10.658Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NsmQeU_Yp12xVJvRJnNDwQ.jpeg" /></figure><p>I first came across in-app environment switching about five years ago from someone I was interviewing. I thought, hey, that sounds cool, it saves having a separate build for each environment. So I went away after the interview and I experimented.</p><p>I quickly realised why I had been using the alternative approach.</p><h3>Two approaches to accessing multiple environments</h3><p>When building an app at scale, you will almost certainly access multiple environments, such as QA, UAT, Staging, Production.</p><p>You need a way of easily testing in each of these environments.</p><ol><li>One approach is to use a different Bundle ID for each environment. This means you can have a QA build running alongside a separate Staging build and a further separate Production build, for example, all on a single device. The choice of environment is made at build time using, say, different Xcode Schemes. Your CI pipeline can trigger and deploy separate builds for all environments, perhaps depending on the branch you’ve pushed to.</li><li>Another approach is to allow switching environments at runtime. The developer or tester then only installs one app, but can choose which environment they’re testing against, by selecting from a menu only visible in non-App Store builds, or using a companion app to launch the target app against a specific environment.</li></ol><h3>Why I recommend against switching at runtime</h3><p>Being able to switch environments at runtime might seem cool and there are some innovative ways to do so without introducing a hidden menu into the app. A companion app can be used to open the target app using a URL scheme with an argument to select the environment. There’s no debating that’s a clever approach!</p><p>But I strongly advise against any switching at runtime. And here is why:</p><h4>1. API Keys for multiple environments in a single app</h4><p>Generally speaking, I recommend against this for security reasons. Having production keys in your test builds, or vice versa, opens up your business to multiple vulnerabilities. This would undoubtedly be picked up in penetration testing.</p><p>But let’s say you would keep production builds separate from non-production builds. Even so, you will still have API keys, URLs and other settings for multiple environments (e.g. Dev, QA, UAT, Staging) embedded in a single build. This increases the complexity of accessing these settings when your app needs them. It means looking them up at runtime to “resolve” for the selected environment.</p><p>Furthermore, a non-production backend such as Staging might deal with production data. Now you have keys in your non-production app which can be used to modify production data.</p><p>🤓<em> Having a separate build for each environment means you can instead </em><a href="https://www.theappbusiness.com/insights/a-robust-multi-environment-build-setup"><em>reference a setting (e.g. API key) through a static immutable property</em></a><em>, which is undoubtedly more robust and requires significantly less code.</em></p><h4>2) Lots of unnecessary complexity</h4><p>Runtime switching would introduce lots of code that would <em>never be used</em> in the App Store build. Yet this code would <em>still be present</em> in the App Store build because you would be unable to wrap this code in #if DEBUG or any other compiler directives. Using compiler directives would require a different Xcode Build Configuration for the App Store build vs. the build for all other environments. That is highly ill-advised as it means your QA and UAT is carried out on a build with a configuration that doesn’t match the one used for your end users. Sounds dangerous to me!</p><p>You might laugh in the face of danger—ha, ha, ha—and use compiler directives, because after all, your second Xcode configuration would differ by just a single -DEBUG flag, right? (Yes, that’s right, until you modify your first configuration and forget to make the same changes to your second.) You’re still introducing otherwise-unnecessary code and complexity, which should be reason enough to steer clear of this approach.</p><p>🤓<em> Less code. Need I say more?</em></p><h4>3) Complicated and confusing internal releases</h4><p>Being able to switch environment at runtime may cause difficulties with internal releases. For instance, you may wish to release QA builds to your testing team and release UAT builds to your stakeholders. With the ability to switch environment in the app, which environment is connected by default? Presumably you’d choose UAT so that your stakeholders don’t need to switch environment. But then your internal testers have to switch to the QA environment after installing.</p><p>There may also be functionality that doesn’t work in one of the environments because, say, WIP backend services haven’t been propagated to the later environments yet. Releasing all environments in a single build will at best lead to confusion and at worst lead to senior stakeholders raising tickets for bugs that are not actually bugs.</p><p>🤓<em> Having a separate build per environment means stakeholders can be given access to the specific builds/environments they need and app deployments can be synchronised with backend environment deployments.</em></p><h4>4) It’s less clear which environment you’re running against</h4><p>When all environments are in a single build, it’s not immediately clear which environment you’re connected to when you open the app. You’d have to presumably call this out in a Help menu or something, leading to more unnecessary code.</p><p>Given that your Staging build is linked to Production data (as is typical), this could lead to mistakes being made on live data without knowing it!</p><p>🤓 <em>With a separate app installed for each environment, the environment can be made clear from the display name, e.g. </em><strong><em>MyApp QA</em></strong><em> and </em><strong><em>MyApp Staging</em></strong><em>. You can even use an </em><a href="https://github.com/HazAT/badge"><em>app icon overlay</em></a><em> to further improve distinction.</em></p><h4>5) Push notifications would be received for wrong environment</h4><p>This is a real pain and can lead to confusion. Confusion can lead to wasted time with bugs raised for no reason and then investigating something that would never happen in reality. I’ll explain…</p><p>Push notifications are linked to a specific Bundle ID. If all environments are within a single app (and therefore single Bundle ID) then you could be running a QA build and receive a push notification related to your Staging account. Opening the push notification might try to deep-link to something that doesn’t exist in the current environment. It’s unclear for which environment the push notification was intended.</p><p>Having separate app builds makes it clear which push notifications are for which app (and therefore which environment). When opening a notification, it will take you directly to the dedicated app for the correct environment.</p><p>🤓 <em>This removes any scope for mistakes. If you find a bug while testing, then you know it’s a bug—you don’t have to waste time figuring out whether or not you had the correct environment set.</em></p><h4>6) You can’t run in different test environments at the same time</h4><p>If your app doesn’t quite behave as expected and you wish to check against another environment, then you have to switch to the other environment in the same app, which means resetting all app state. You will lose your progress in the app: what you’d searched for, which tab you were on, etc. and you’d have to sign in again. Then you have to do it all again to switch back to the environment you were originally testing against.</p><p>You have to hard reset the whole app when switching environments, because you can’t risk state being leftover from the previous environment which would undoubtedly lead to bugs.</p><p>🤓 <em>A separate app for each environment means you can easily switch to another app to test something in another environment without losing state in either app/environment.</em></p><h4>7) Harder to maintain</h4><p>The fact that environment switching requires you to “hard reset” the whole app when switching environments introduces more maintenance complexity. There are lots of bugs that could come from having corrupt data leftover in memory from a previous configuration, so all state must be cleared out.</p><p>As the project grows and new state is added here and there, there’s a greater risk that some state is not removed when switching environment. Any object that is storing state should have its state reset.</p><p>You may have third-party dependencies that are configured based on your environment, e.g. a different API key for your Analytics provider. All such third-party dependencies have to be reinitiated when switching environments.</p><p>Because of the added maintenance complexity, you would be expected to write more documentation to explain how the environment switching works and what must be done when adding new state, to ensure that state is cleared out upon switching environment.</p><p>🤓<em> Having a separate build per environment is simple for anyone to understand. It requires no additional documentation and introduces no additional maintenance complexity.</em></p><h3>Conclusion</h3><p>Being able to switch between several environments in a single app build will introduce a lot of unnecessary code. That is code that someone has to spend time writing and later maintaining. And for what? In my (albeit subjective) opinion, this extra effort would be for an experience that is worse for developers and worse for testers.</p><p>The only benefit I can see is that it’s less overhead for Apple Developer Account administrators who, in the case of a single build for multiple environments, would only have to create a single provisioning profile. For me, that’s not enough to outweigh all the disadvantages listed above.</p><p>I’m keen to hear others’ arguments though, so please leave a comment!</p><p>And if you’re interested in how we build robustness and reliability into our apps at TAB, why not <a href="https://www.theappbusiness.com/careers">introduce yourself</a>?</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3a798a421dcf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/switching-app-environment-at-runtime-a-counterargument-3a798a421dcf">Switching App Environment at Runtime—A Counterargument</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I followed these 7 simple steps and became an iOS coding test BOSS!]]></title>
            <link>https://medium.com/kinandcartacreated/i-followed-these-7-simple-steps-and-became-an-ios-coding-test-boss-7da963c3a40d?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/7da963c3a40d</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[codingbootcamp]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Wed, 31 Oct 2018 13:01:58 GMT</pubDate>
            <atom:updated>2018-10-31T13:03:47.824Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*M58-tktp1LMdzDitH-TQbQ.png" /></figure><p>So you took the bait. Your route to success starts here! 🤑 But unlike the many get-rich quick schemes promised on the side-panes of particular websites, I hope to actually <em>deliver</em> on my click-bait.</p><p>When completing an iOS coding test, there are a number of simple ways to make your submission stand out and give reviewers confidence that you know what you’re doing.</p><p>The common theme here is:</p><blockquote>If you want someone else to love your code, then you need to love it yourself.</blockquote><p>By following the suggestions below, interviewers will barely need to look at what your code actually does. Good programming techniques can be taught after you’ve landed the job. It’s more difficult to teach someone to love their code. But it’s so important! After all, you shouldn’t need to be taught this, given this is your chosen career. 🤓</p><p>I don’t want this article to come across as arrogant; I’m not suggesting going through a company’s hiring process is easy. I just want to help people that are completing coding tests to make their submission the best it can be. I think there are a few very simple ways to do that.</p><p>It shouldn’t take a long time to make a simple app as part of a coding test—depending on experience of course—but you don’t want it to appear rushed. Show your code the love it deserves. It’s easy to keep your code clean and it all starts with the app delegate.</p><h3>UIApplicationDelegate</h3><p>Usually known as the AppDelegate, this is the entry point into your app. As such it’s the first place interviewers look. If your code was a book, this would be the first page. Show it the love it deserves and an interviewer will love it too.</p><p>For a simple test, your AppDelegate could look as simple as this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1ce1453994bebdf8bddf2708e1a0b961/href">https://medium.com/media/1ce1453994bebdf8bddf2708e1a0b961/href</a></iframe><p>The window property is required if you’re loading your interface from a storyboard. You don’t have to load your interface from a storyboard, but for a short coding test it’s the simplest thing to do. It’s the default when creating a new Xcode project and you probably won’t be required to create too many screens in a simple test. There are advantages to loading from a .xib, but the pros and cons are something you should feel confident talking about at interview stage rather than demonstrating in your test submission.</p><p>Even the application(_:didFinishLaunchingWithOptions:) method is not necessary. (It’s an optional method in the UIApplicationDelegate protocol.)</p><p>The AppDelegate.swift file that’s created by default with a new project comes with a load of commented-out method implementations that don’t do anything. Get rid of them. This rule should be applied across the whole of your project’s codebase…</p><h3>Get rid of empty methods</h3><p>By empty methods, I mean methods that only call the super class’ implementation and/or only contain comments. These are usually methods that were created for you by Xcode when you created a file from a template. If you don’t need these methods then delete them.</p><p>This is what a UIViewController subclass will look like when you create it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3aca5127dae84128d3032f2ead6b13cb/href">https://medium.com/media/3aca5127dae84128d3032f2ead6b13cb/href</a></iframe><p>The first thing you should do when creating this file is delete the template code. You’ll know if and when you need to implement viewDidLoad and you’ll know to call the super implementation (well, you should know). Don’t clutter your codebase with comments unless you think they will benefit the prospective employer reviewing your code. They probably already know that the viewDidLoad method is where you “do any additional setup after loading the view.” So remove the comment and remove the method if you don’t need it. (And of course, remove the comment block that includes the prepare(for:sender:) method.)</p><p>Before submitting a test, go through the codebase with a fine-tooth comb for any code that you wrote as part of “work in progress” that may no longer be needed. If code is no longer needed, don’t just comment it out, delete it. It’s also best not to leave comments to explain what you’re doing. Code should be self-documenting, so if you find yourself leaving a comment, instead try to find another way of writing the code to make it more clear what’s happening. Often this is as simple as moving the code into separate method.</p><p>Another place to look for redundant code is in your unit test target. If you selected to create unit tests during project initialisation, that’s great, but please don’t just submit the auto-generated template methods. It’s such a tease for the reviewer that wants to see tests. If you don’t need the setUp and tearDown methods, delete them. Reviewers don’t want to see the below submitted as part of a coding test.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/235f8c8a4fb8582dd34d32e32f5c7f43/href">https://medium.com/media/235f8c8a4fb8582dd34d32e32f5c7f43/href</a></iframe><h3>Make it simple</h3><p>It’s not always easy to make something simple. Making something simple is a challenge and when doing so, you’re doing it for the benefit of the consumer:</p><ul><li>Make a user interface that’s simple to navigate by a user.</li><li>Make an API that’s simple to consume by another developer.</li><li>Make a presentation that’s simple to understand by your audience.</li><li>Make a test project that’s simple to review by someone that’s probably reviewing a lot of tests.</li></ul><p>The last point there is much simpler than the others. Making a simple user experience is a challenge. Making a test project simple to review should be simple itself. You don’t need to demonstrate your knowledge of every architecture pattern under the sun.</p><p>You can talk about your love of MVVIP-UPVCA at interview stage. 😎</p><p>A reviewer shouldn’t mark you down for fulfilling their requirements in the simplest way possible and often this means using the MVC pattern promoted in most Apple documentation. Don’t worry, you can still demonstrate your in-depth knowledge of the <a href="https://en.wikipedia.org/wiki/SOLID">SOLID principles</a>! You can show you understand the advantages of dependency injection and you’ll have more time to do so if you’ve used a simple architecture. You might even save enough time to implement the odd unit test. I’ve seen too many test submissions with some mutant variation of the VIPER architecture, but without a single unit test or even an app icon.</p><p>Being pragmatic is important in programming. You need to determine when an elaborate architecture is appropriate. For an app of two or three simple screens, it’s probably overkill. Don’t just keep it simple, <em>make</em> it simple.</p><p>It’ll be better use of your time to group related files into Xcode groups (and therefore directories on disk). This is another great way to show the reviewer how you keep yourself organised and it makes reviewing your project a breeze. But again, don’t go overboard. If every .swift file is in its own group then you’ve misunderstood the definition of grouping. There are lots of different ways to group and there’s no right or wrong, within reason. For a simple project, I suggest grouping your model objects together; grouping any networking/backend-related components; grouping user interface components by feature/screen. Go with what you’re comfortable with and make sure you have a rationale for how you’ve organised your files.</p><p>Removing empty methods also contributes to making your app simple to review and the methods you have should be kept as small as possible. To “keep methods small and files smaller” is an impossible challenge, but I dare you to try.</p><p>There’s no need for three or more levels of indentation. Instead call out to another method. Because methods are named, they make your intention much more clear than <em>yet another level of indentation</em>. If you’re calling out to another method in the same file, you should declare that method private…</p><h3>Understand access control and mutability</h3><p>Demonstrating that you understand access control and mutability can go a long way with reviewers. Don’t give them anything to find fault in.</p><p>This is Swift best practice 101:</p><ul><li>Make everything private first, only exposing when necessary</li><li>Make everything let first, only use var declarations when necessary</li><li>Make your class types final if you’re not subclassing them</li></ul><p>If you’re unsure on any of the above, go with the most restrictive first (private, let, final) and increase flexibility only if really needed.</p><p>For example, if you’re not sure what should be private, then make everything private, hit Build and see what fails to compile so you know what must be exposed. Any code that isn’t private should just be left with no access modifier at all; no need to declare anything internal as it’s the default and it’s unlikely you’d need to declare anything public in a coding test. But anything that <em>can</em> be private <em>should</em> be.</p><p>Any views or subviews (such as those declared with the@IBOutlet decorator) should definitely be private. Incidentally, @IBOutlet properties are the only excuse for implicitly unwrapped optionals or any type of forced unwrapping/casting. I’m referring to the dreaded exclamation mark…</p><h3>Avoid forcing! <em>anything</em></h3><p>“Unconditional unwrapping” (or forced unwrapping) is where you incorrectly assume an optional won’t be nil at runtime. A common example is retrieving the first or last element in a collection, e.g. let heroImage = images.first!. Always assume the worst. Even if you’ve set the images up from a static list, you cannot guarantee it won’t crash at runtime. Always assume the worst! It shows that you understand the use of optionals and you understand that just because it doesn’t crash now, that doesn’t mean it won’t crash if someone changes the code later. Use if let or guard let syntax to ensure you have the non-optional you require.</p><p>Forced type casting is where you incorrectly assume one type can be treated as another type at runtime. A common example is when reading from a [String: Any] type dictionary. You’ll read values like so:</p><pre>let name = dictionary[&quot;name&quot;] as! String<br>let age = dictionary[&quot;age&quot;] as! Int</pre><p>Using as! is dangerous. Even if you’re confident it won’t crash at runtime, you don’t have the guarantee of Swift’s strong type system. So always assume the worst and safely unwrap these using as? like so:</p><pre>guard let name = dictionary[&quot;name&quot;] as? String,<br>    let age = dictionary[&quot;age&quot;] as? Int else {<br>        return<br>}</pre><p>Implicitly unwrapped optionals are those declared with a ! next to their type when originally defined. A common example is a view model that you will provide later, so you know it’s gonna be there, right? Right?! Wrong! Implicitly unwrapped optionals are a lazy hack to get your code to compile, e.g. var viewModel: ProfileViewModel!. The exclamation mark on the end tells the compiler you’ll give this a value later and it can assume it won’t be nil, so the compiler won’t require you to do the if let/guard let dance. But it’s dangerous. You can avoid this either by declaring your property as a normal optional with ? after the type, or by ensuring the property is passed in on init, so you don’t have to use an optional at all. The latter is preferred because it means you can declare the property with let and you don’t need the if let syntax because you‘ve <em>explicitly</em> defined that it cannot be nil.</p><blockquote>@IBOutlet properties are a commonly accepted exception to the above. I once saw a project where even these were declared optional, but I think that’s overkill. The way I see it is this will definitely come out in testing and you’ll have bigger problems on your hands if your view doesn’t exist. At any rate, you certainly won’t be marked down in a coding test for declaring your @IBOutlet properties as implicitly unwrapped optionals. Just make sure they’re private. Subviews are an implementation detail and should not be exposed to the outside world. If you want to allow another object to modify state of a subview, such as setting text on a label, then create a setter method or property (using set/get). This makes your intention explicit and means that the outside world cannot accidentally corrupt your view, e.g. changing a label’s background colour.</blockquote><h3>Meet the requirements</h3><p>If you don’t follow any of my previous suggestions, you should at least follow this one. My previous suggestions are code-related and following them will make your submission stand out.</p><p>This suggestion will ensure the reviewer actually looks at the code you’ve slaved over and doesn’t just reject it immediately.</p><p>The first thing I do when reviewing a test submission is to run the app in the simulator, so you should ensure your project:</p><ul><li>builds on the latest version of Xcode</li><li>builds and runs out-of-the-box, without the reviewer having to install dependencies (other than Xcode of course)</li><li>looks as you expect on all supported screen sizes and devices</li><li>looks as you expect when the device is rotated, unless you’ve explicitly disabled rotation</li></ul><p>Then make sure your project meets the requirements laid out in the test description. Check each of the requirements and double check that you’ve covered them.</p><p>If you don’t understand any of the requirements given to you by a prospective employer, you should check with your contact at the company. Don’t make them feel bad for not explaining the criteria clearly enough, after all you want them to give you a job, so be nice. Politely ask for clarification and feel free to go back and forth as much as necessary until you fully understand what’s required of you. This demonstrates a collaborative way of working.</p><p>If you cannot meet the requirements, don’t worry too much, presumably it’s due to a lack of experience and that’s fine! There’s always something to learn, so don’t worry! Explain the difficulties and explain what you tried. Write it up in the README.md file or in an accompanying email. If you notice bugs that you don’t know how to fix, let the reviewer know and hopefully they’ll work with you at interview stage to find a solution together.</p><p>If you don’t explain, then the reviewer will have no choice but to assume you either missed the requirement(s) completely or chose to ignore them. Both of which are equally as bad.</p><p>Once you’re happy you’ve met the requirements and your codebase is as clean and tidy as it can be, then you’re ready to submit, right? But…</p><h3>Don’t submit a test, submit an app!</h3><p>You’re applying for a developer role and you want to make apps, right? So make an app! An app has an app icon. Sometimes even a catchy title. Show that you take pride in your work.</p><p>There are plenty of free tools online to convert an image into all the necessary sizes for iOS app, such as <a href="https://makeappicon.com">https://makeappicon.com</a>.</p><p>You wouldn’t upload an app to the App Store with no icon, so why treat a job application any differently?</p><p>The same applies to the app name. Perhaps this isn’t so important, but why not surprise the reviewer with a creative app name. Don’t include the word Test in your app name. You wouldn’t submit to the App Store with this name and it can get confusing with test targets which by default append the Tests suffix (e.g. RecipeCodingTestTests). If you’re asked to make a recipe app, show your creativity with the app name (unless the requirements state otherwise)… Recipeasy, Recipe Idol, Recipe For Me, Bake With XYZ where XYZ is the company name to which you’re applying. These are all better names than RecipeCodingTest.</p><p>Pretend you’re wrapping up your project ready for the App Store, but also for others to collaborate on in future. Of course this won’t be the case with your coding test, but in reality it’s very unlikely you’ll be working alone once you start the job. Adding a README.md file isn’t always required, but it’s so easy, so why not? You only need the project name and brief description. But for the purpose of the hiring process, you could use the readme to describe any challenges you faced or anything you’d do in the future, i.e. a project roadmap or TODO list. If you write a TODO list, ensure it lists <em>future</em> features that you’ve thought of <em>yourself</em>, features that are <em>out of scope of what was asked of you</em>. Don’t submit an incomplete test or explain that you ran out of time. And remember the readme is for project collaborators (i.e. the reviewer). The readme is not an App Store description for your users.</p><p>While you’re applying the polish, it’s as good a time as any to check that any images in your app are not stretched. Set any image view’s content mode to “Aspect Fill” in Interface Builder or set it to .scaleAspectFill in code.</p><h3>To summarise…</h3><ol><li>Keep the app delegate tidy, it’s the entry point to your project.</li><li>Remove empty methods and methods that only call the superclass implementation; remove any commented work-in-progress code.</li><li>Make it simple to review; keep the architecture simple and keep the workspace organised.</li><li>Demonstrate your understanding of the importance of access control and mutability; if in doubt, go with private/let/final.</li><li>Avoid forced unwrapping, forced type casting and implicitly unwrapped optionals.</li><li>Meet the demands of your prospective employer; show that you can follow instructions; don’t be afraid to ask them for help and be honest about what you don’t know—everyone has room for improvement!</li><li>Wrap it up and tie it in a bow; give it an app icon and a name that shows your personality and creative spirit.</li></ol><h3>Next steps</h3><p>I believe the above suggestions can followed by anyone, regardless of experience. But there are of course lots of things you can do over and above this to demonstrate more experience if you have it, such as demonstrating an understanding of Git, unit testing, UI testing, Fastlane, SwiftLint and “hot” language features such as Codable.</p><p>Whether you are actively applying for jobs or you’re recruiting and reviewing tests yourself, I hope you found this article useful. Please share if you think others will find it useful too!</p><p>Please check out more posts on the <a href="https://edit.theappbusiness.com/tagged/engineering">TAB Engineering blog</a> and <a href="https://twitter.com/dodsios">follow me on Twitter</a> for more of the same. If you’re interested in joining our talented and passionate iOS team, then please message me!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7da963c3a40d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/i-followed-these-7-simple-steps-and-became-an-ios-coding-test-boss-7da963c3a40d">I followed these 7 simple steps and became an iOS coding test BOSS!</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making the Most of Swift.KeyPath]]></title>
            <link>https://medium.com/kinandcartacreated/making-the-most-of-swift-keypath-1c3d8c8c1d25?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/1c3d8c8c1d25</guid>
            <category><![CDATA[engineer]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Wed, 03 Oct 2018 08:55:16 GMT</pubDate>
            <atom:updated>2018-10-03T09:48:37.551Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/701/1*x6R7NgyaqLkk3ik-1yw58g.png" /><figcaption>You’re close, but it’s not the one.</figcaption></figure><p><strong>DISCLAIMER:</strong> This is a proof of concept and by no means am I promoting the approach laid out below. I might offer an opinion at the end. 😇</p><h4>What I’m playing around with…</h4><p>Every time I write a map or sorted (etc.) in a Swift project I think: Wouldn’t it be nice if I could simplify this with a key path?</p><p>i.e. it would be nice to write people.map { $0.address.city }</p><p>as people.map(\.address.city)</p><p>I thought about submitting a proposal through the Swift Evolution process but noticed <a href="https://forums.swift.org/t/pitch-keypath-based-map-flatmap-filter/6266">it has already been discussed in great length</a>.</p><h4>Micro zoom out</h4><p>⚡️ The KeyPath type was <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md">introduced in Swift 4</a>. But I don’t find a lot of use for it in everyday coding, so I started playing around to see if I could make more use of it.</p><h4>Approach</h4><p>I’ve taken the approach of defining an operator to convert a key path into a function that can be passed to the standard library methods. The alternative would be to overload those methods.</p><p>So instead of implementing my own overloaded version of map etc. I convert the key path KeyPath&lt;A, B&gt; into the necessary function type (A) -&gt; B.</p><p>The benefit of this approach is that I don’t need to overload all the variations of each method, i.e. I don’t need to overload map, compactMap and flatMap. I just implement one operator for all methods with the same signature.</p><p>I created a Swift Playground to try it out and thought it would be worth sharing, so here we go…</p><h4>First I need a data model to play with…</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/97291d1d9a54f6e099f4a2915230b9f5/href">https://medium.com/media/97291d1d9a54f6e099f4a2915230b9f5/href</a></iframe><h4>What mapping looks like…</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bd609e032cac4f94508b8e40b849baa1/href">https://medium.com/media/bd609e032cac4f94508b8e40b849baa1/href</a></iframe><h4>The new syntax for sorting…</h4><p>For the sake of my proof of concept, I sort such that elements at the start of the list are “less than” elements at the end of the list, i.e. I sort using the provided key path and the &lt; operator. If the reverse was required, you could do the same and add .reversed() to the end.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4e143307357d2937c390ece92d59a6f2/href">https://medium.com/media/4e143307357d2937c390ece92d59a6f2/href</a></iframe><h4>Filtering using Boolean properties…</h4><p>Filtering is supported for properties (key paths) that return a Bool. So for example, we could filter all strings where isEmpty is true, or we could filter all controls where isEnabled is true, or all views where isHidden is true.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8ddce5fb8149d5675d1e400bafc4a7be/href">https://medium.com/media/8ddce5fb8149d5675d1e400bafc4a7be/href</a></iframe><p>A load of other methods have the same signature as filter, e.g. first(where:):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/23a25584157c5f21a910e11a259bf041/href">https://medium.com/media/23a25584157c5f21a910e11a259bf041/href</a></iframe><p>This can be further enhanced with a simple extension on Bool, so as well as filtering all empty strings, we can filter all non-empty strings:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/60a0075695799c262db3440b2a6f6e5c/href">https://medium.com/media/60a0075695799c262db3440b2a6f6e5c/href</a></iframe><h3>Conclusion</h3><p>It looks like this won’t be added to the standard library any time soon and I don’t think that’s a bad thing.</p><p>On the surface this syntactic sugar seems nice and it’s fun to play around with. But on reviewing a very large codebase I’m working on, I only found 54 occurrences where I’m using the syntax map { $0.some.key.path }. And is it really that ugly?</p><p>Overloading the methods is less elegant because it requires all individual methods to be overridden. But implementing an operator to convert a key path to a function has its disadvantages too. There may be an example of a function with the same signature as, say, map, but to which it wouldn’t make sense to pass a key path.</p><p>Oh and of course custom operators themselves are controversial (but I’m not here to offer an opinion on that 😉).</p><p><strong>Bottom line is I’ll keep this as a proof of concept for now :)</strong></p><p>Hope you enjoyed this article, <a href="https://twitter.com/dodsios">follow me on Twitter</a> for more of the same, or check out the other articles on the <a href="https://edit.theappbusiness.com">TAB blog</a>.</p><p>Full Gist is <a href="https://gist.github.com/samdods/00d6a14a6430d824281822fdc2419672">here</a>. Swift Playground is <a href="https://github.com/samdods/KeyPathPlayground/tree/master">here</a>.</p><p>P.S. If you’re excited by advancements in Swift and iOS and you want to be part of our passionate team, head on over to our <a href="https://www.theappbusiness.com/join">hiring page</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1c3d8c8c1d25" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/making-the-most-of-swift-keypath-1c3d8c8c1d25">Making the Most of Swift.KeyPath</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[User Notifications in iOS — bringing the app out of the app]]></title>
            <link>https://medium.com/kinandcartacreated/user-notifications-in-ios-bringing-the-app-out-of-the-app-38573eeedb67?source=rss-195b086ce5f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/38573eeedb67</guid>
            <category><![CDATA[push-notification]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Sam Dods]]></dc:creator>
            <pubDate>Thu, 28 Jun 2018 10:31:30 GMT</pubDate>
            <atom:updated>2018-06-29T08:49:18.699Z</atom:updated>
            <content:encoded><![CDATA[<p>User notifications in iOS have evolved drastically over the last few years. Something that changed very little for the first seven iterations of the operating system has definitely seen some love from Apple in recent updates.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_muvfj7_GvBoiRjA0tsXQA.png" /><figcaption>Early example of a user notification in iOS (from WWDC 2010 video archive)</figcaption></figure><p>Notifications were first introduced with iOS 3 back in 2009.</p><p>In 2014, iOS 8 brought with it actionable notifications, and the ability to enter text (e.g. reply to a message).</p><p>And in 2016, iOS 10 allowed for media and other rich content to be shown in notifications. It also provided the ability to modify the content received before showing it to the user (which, for example, allows messages to be decrypted before being shown).</p><p>In 2018, iOS 12 was announced, which will allow for an even richer and more engaging user notification experience. It will allow:</p><ul><li>full interactivity within the notification, e.g. to move around a map, to toggle switches, to flick through multiple images;</li><li>the ability to modify the “actions” supported while the notification is visible, e.g. to give secondary actions, based on the selection of primary action;</li><li>custom grouping options, e.g. to separate time-sensitive alerts from advisory updates;</li><li>and, provisional authorisation (also known as “automatic trial”), which may increase the chance of a user opting in to receive notifications.</li></ul><h3>But why don’t we see more rich notifications?</h3><p>Two years on from Apple’s previous big update to notifications, and so many apps, including Facebook and WhatsApp, still don’t take advantage. If a friend tags me in a photo on Facebook, it would be great to see the photo in the notification. And if a friend shares a photo on WhatsApp, I’d like to see the image without launching the app.</p><p>You might ask, <em>“why give away all the information in the notification? “We want to drive users to open our app!”</em></p><p>But the way I see it, in a world of notifications, we need to make ours stand out! And if we engage people with the notification, they are more likely to open the app.</p><p>Or if the app supports another service, and the aim is to simplify a common user journey, then removing the need to ever open the app is even better.</p><blockquote>Apps with a business model based on advertising revenue will always prefer users to open the app. But there’s still value in engaging the user with more helpful notifications, which may encourage them to open the app.</blockquote><h3>Evolution by Example</h3><p>I’m going to look at the evolution of the notification, from its simplest form, through to a rich, engaging, user-friendly experience. And I’ll give my recommendations on how to group notifications, and when to use provisional authorisation.</p><p>For this example, I’ll use the concept of an energy provider’s app.</p><h4>The humble text-only notification</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/462/1*0eXuHyCFQv2e8QQT51nzBA.png" /><figcaption>An example of a simple text-only notification</figcaption></figure><p>Above is how the simplest form of user notification will look on iOS 12. You might use this notification to inform the user their new bill is available, or to remind them it’s time to submit a meter reading.</p><h4>Improving the experience with custom actions</h4><p>Let’s take the example of reminding the user to submit a meter reading. We can use notification actions (introduced in iOS 8, 2014) to give the user the option to submit now, which would launch the app, or to snooze the notification, if now’s not a good time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/465/1*tYCaN7LdThvN_a4MsSAWsg.png" /><figcaption>Notification with custom actions</figcaption></figure><h4>Adding visuals</h4><p>Since iOS 10 was released in 2016, we’ve been able to make our notifications much richer, adding images, videos, maps, or custom animations.</p><p>Let’s look at the example of notifying the user that their balance has been updated.</p><p>Sending a text-only notification would invite the user to open the app. But if we present to them something more useful, we can remove the need to open the app at all.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*MbWDQMuMyg0n9KpXZvM5fg.gif" /><figcaption>Notification with custom visual content</figcaption></figure><p>Note that the notification also has a thumbnail image, prompting the user that there is useful, visual content within the notification.</p><blockquote>Dynamic animation within the notification is a great way to capture the user’s attention. It’s important not to over-complicate the notification. It should just be a light summary, highlighting important information.</blockquote><h4>Going the extra mile</h4><p>I really believe that notifications are a great way to engage our users. If the user has authorised us to send them notifications, I think we owe them a rich user experience.</p><p>And as more apps pick up on this, any app that doesn’t will stick out like a sore thumb — like the popular social media and messaging apps.</p><p>Here is how I envision an energy provider could take advantage of notifications to improve the experience for their users.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F277431538%3Fapp_id%3D122963&amp;dntp=1&amp;url=https%3A%2F%2Fvimeo.com%2F277431538&amp;image=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F710203255_960.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=vimeo" width="1080" height="1626" frameborder="0" scrolling="no"><a href="https://medium.com/media/cc020a58962bac5d7e26d4d5da55650b/href">https://medium.com/media/cc020a58962bac5d7e26d4d5da55650b/href</a></iframe><p>In this concept,</p><ul><li>we remind the user that it’s <em>that</em> time again;</li><li>we give them the option of setting a reminder (e.g. in 2 minutes while I nip out to the garage; or tomorrow when it might be more convenient);</li><li>we also allow them to submit right now, from within the notification, without launching the app;</li><li>and a moment after submitting, they receive a new notification revealing their amended account balance with a three-month comparison.</li></ul><h3>Further Considerations</h3><p>It’s crucial to be considerate towards our users, given iOS 12 makes it easier than ever to silence or disable notifications. Luckily iOS 12 introduces more ways to be considerate with notifications.</p><h4>Grouping</h4><p>iOS 12 automatically groups all notifications of the same app, so the user will just see the latest notification, visually stacked in front of all other unread notifications. Tap the notification to reveal all the notifications in the stack. App developers can choose to customise the way their notifications are grouped, for example, the iOS News app groups notifications by News Outlet. Notice in the example below, CNET notifications are grouped separately from notifications for The Telegraph. But these are all notifications from the same app, News.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*qHPg2lbUo2zux1keu_yVUA.gif" /><figcaption>Grouped notifications in iOS 12</figcaption></figure><p>In the energy provider example we see two different types of information we’re giving to the user — meter reading reminders, and balance updates.</p><p>We should think about grouping meter reading reminders separately from balance updates, because we want to attract the user’s attention.</p><p>The default is to combine all notifications from a single app into one group. It’s up to us as developers to think about how we could group types of notification to improve the user experience, and make more important messages stand out.</p><h4>Provisional authorisation</h4><p>In iOS 12, we are no longer <em>required</em> to ask in advance for the user’s permission to send them notifications. We now have the option of sending notifications quietly. Notifications that are delivered quietly will appear in Notification Center, but with no banner or sound.</p><p>When notifications are delivered quietly, the user can later decide to deliver them prominently:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/490/1*lQ5r11cK3ybvIQKE8-dcUQ.png" /><figcaption>Managing notifications in iOS 12</figcaption></figure><p>With the changes to grouping, it’s much more likely that a user will see these quietly-delivered notifications in Notification Center, because it won’t be flooded with countless unread notifications from the same apps. When the user finds the notification, they can then choose to show these prominently in future, disable completely, or continue receiving them quietly. This is also referred to as <strong>automatic trial</strong>.</p><p>If we don’t ask for permission up front, then all notifications will be delivered quietly. We cannot control on a case-by-case basis.</p><p>When considering provisional authorisation, it’s worth questioning: <em>would we stand a better chance of users giving permission if we send notifications quietly to being with?</em></p><p>If you do send “quietly” to begin with, and your notification helps the user achieve their desired outcome sooner and more easily, then they will quickly decide to receive these “prominently” in future.</p><h3>In Summary</h3><ul><li>Consider adding rich content to your notification, removing the need to open the app</li><li>If you have custom content to show, add a custom thumbnail</li><li>Instead of pushing the user to the app to complete a task, consider whether an interactive notification can improve the user experience</li><li>Group important, actionable notifications separately from informative updates</li><li>Consider sending “quiet” notifications for provisional authorisation, if the notifications are not user critical</li></ul><p>Thanks for reading! You can find me on Twitter <a href="https://twitter.com/dodsios">here</a>. And find out what we’re up to at TAB <a href="http://www.theappbusiness.com">here</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=38573eeedb67" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/user-notifications-in-ios-bringing-the-app-out-of-the-app-38573eeedb67">User Notifications in iOS — bringing the app out of the app</a> was originally published in <a href="https://medium.com/kinandcartacreated">Kin + Carta Created</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>