<?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 Kane on Medium]]></title>
        <description><![CDATA[Stories by Kane on Medium]]></description>
        <link>https://medium.com/@KaneCheshire?source=rss-203911794be4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*Ee31497CFxryOkY7TMtblw.jpeg</url>
            <title>Stories by Kane on Medium</title>
            <link>https://medium.com/@KaneCheshire?source=rss-203911794be4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 24 Apr 2026 03:00:36 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@KaneCheshire/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[Recreating Swift’s Result type in Kotlin]]></title>
            <link>https://medium.com/@KaneCheshire/recreating-swifts-result-type-in-kotlin-f0a065fa6af1?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/f0a065fa6af1</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[kotlin-beginners]]></category>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[android-app-development]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Wed, 09 Sep 2020 17:57:07 GMT</pubDate>
            <atom:updated>2020-09-09T18:02:25.288Z</atom:updated>
            <content:encoded><![CDATA[<p>In Swift, I use the Result type extensively. Mostly for async callbacks, but it’s generally a nice, tidy and consistent way to provide a value that can either be a success or failure as a result of calling a function.</p><p>When I started learning Kotlin, I found that there is a Result type included (<a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/">since Kotlin 1.3</a>), but to my dismay you cannot (<a href="https://stackoverflow.com/questions/52631827/why-cant-kotlin-result-be-used-as-a-return-type">by default</a>) use this class as a return value for a function.</p><p>I have never been happy with Kotlin’s built-in version of the Result type, anyway. Having to check if isSuccess or isFailure, null-check if the success or failure value exists or use the fold function seems archaic and not really necessary in neither Kotlin or Swift thanks to their generics.</p><p>So I set out to create my own version of Result in Kotlin, and to do that I used Kotlin’s closest equivalent to Swift’s powerful enums, a sealed class:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/936ad384ad8cd35567b1f5a079c406c6/href">https://medium.com/media/936ad384ad8cd35567b1f5a079c406c6/href</a></iframe><p>The use of generics here looks quite verbose (and a bit overwhelming), but it’s required, since the way sealed classes work is by creating subclasses of the sealed class. Here’s how you’d use this new Result type:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/13b379b092e4acc2824b61ca0ab922ec/href">https://medium.com/media/13b379b092e4acc2824b61ca0ab922ec/href</a></iframe><p>In the above code, we have two functions. One function that returns a Result with a Success type of String, and another function that returns a Result with a Success type of Int. Both functions return a Failure type of Error, which is just another sealed class that implements Throwable (since our Result’s Failure type requires a type that is Throwable):</p><pre>sealed class Error : Throwable() {<br>    object CouldntDoSomethingElse : Error()<br>}</pre><p>Although the declaration for the Result class looks complicated with generics, we only need to explicitly define the Success and Failure type once when declaring the return type of each function.</p><p>When it comes to actually returning either Success or Failure, you can just pass the appropriate value and Kotlin handles the rest.</p><h4>Why use sealed classes?</h4><p>Sealed classes are the closest match to Swift’s awesome and powerful enums. You can use an instance of a sealed class in a when statement like you would a switch statement in Swift, and if you’re using the result of the when statement, Kotlin will make sure you’ve either handled every branch (Swift calls these cases), or added a fallback else branch (like Swift’s default fallback):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/39c2d02d17b28a6312ddf44091e23781/href">https://medium.com/media/39c2d02d17b28a6312ddf44091e23781/href</a></iframe><p>And that’s all there is to it really. Here’s the default Kotlin equivalent for comparison:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2ac210bff839d04615b3e1d69bfa8f1f/href">https://medium.com/media/2ac210bff839d04615b3e1d69bfa8f1f/href</a></iframe><p>That code actually won’t compile without jumping through some hoops because you can’t use Kotlin’s Result type as a return value anyway, but comparing it, I feel like my version of the Result type is cleaner and allows you to use a when statement, which is very common to see across a Kotlin codebase. If you needed fold for functional programming it would be trivial to add an extension onto my Result class:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/43513fe6f6f2fb37efeb8fee9a5085bd/href">https://medium.com/media/43513fe6f6f2fb37efeb8fee9a5085bd/href</a></iframe><p>Another bonus of my Result type is you know what type the Throwable will be, because you’ve explicitly declared it in the return type. If you need it to be less restrictive/more generic like the built-in Result type (which doesn’t let you specify the type of Throwable at all), you can still just declare the Failure type as Throwable:</p><pre>fun doSomething(): Result&lt;String, Throwable&gt; {<br>    return Result.Failure(IllegalStateException(&quot;Now I can use any Throwable here!&quot;))<br>}</pre><p>Enjoy!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f0a065fa6af1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Sticky UI in Android Bottom Sheet]]></title>
            <link>https://medium.com/@KaneCheshire/sticky-ui-in-android-bottom-sheet-3d65ea1d20dc?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/3d65ea1d20dc</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[motionlayout]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[androiddev]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Wed, 19 Aug 2020 12:50:10 GMT</pubDate>
            <atom:updated>2020-08-19T12:50:10.421Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vaa_M1xMKXH48_sU" /><figcaption>Photo by <a href="https://unsplash.com/@picoftasty?utm_source=medium&amp;utm_medium=referral">Mae Mu</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Sticky UI in Android bottom sheets</h3><p>Over the past few months I’ve been working on porting one of my <a href="https://apps.apple.com/us/app/ride-track-your-esk8-rides/id1271234198">native iOS apps</a> to Android, and I’ve been learning a lot about how Android works as a platform.</p><p>I’m now far along enough into development that I’m starting to work on refining the UI, and one of my challenges has been to create a bottom sheet where some UI appears to “stick” to the bottom.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QHL8BF4wv2JTHVupdEXZDA.gif" /><figcaption>Sticky!</figcaption></figure><p>After a bit of research I couldn’t find a simple solution so ended up coming up with my own. I’m pretty happy with the result, and it paves the way for more complicated UI in the future too!</p><p>In this post, I’ll show you just how easy it is using the new and glorious <a href="https://developer.android.com/training/constraint-layout/motionlayout">MotionLayout</a>.</p><h4>Setup</h4><p>Before we can continue we need to add a couple of dependencies to our module’s build.gradle file (in this simple case, the module is just the app itself):</p><pre>// For MotionLayout<br>implementation &#39;androidx.constraintlayout:constraintlayout:2.0.0-rc1&#39;</pre><pre>// For CoordinatorLayout<br>implementation &#39;com.google.android.material:material:1.2.0&#39;</pre><p>At the time of this post, the latest version of the constraintlayout library that includes MotionLayout is 2.0.0-rc1, so that’s what we’ll use for this tutorial.</p><h4>Layout</h4><p>The next step is to update our layout file to add a bottom sheet with a button inside. Since this is a simple example, we’ll just add this to the MainActivity’s activity_main.xml layout file:</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;<br>&lt;!-- Set the root layout to be a Coordinator Layout. --&gt;<br>&lt;!-- In my actual app, it&#39;s not the root layout, but in this simple example it can be. --&gt;<br>&lt;androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;<br>    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;<br>    xmlns:tools=&quot;http://schemas.android.com/tools&quot;<br>    android:layout_width=&quot;match_parent&quot;<br>    android:layout_height=&quot;match_parent&quot;<br>    tools:context=&quot;.MainActivity&quot;&gt;<br><br>    &lt;!--  Add a MotionLayout as the bottom sheet with a BottomSheetBehaviour  --&gt;<br><br>    &lt;androidx.constraintlayout.motion.widget.MotionLayout<br>        android:id=&quot;@+id/bottom_sheet&quot;<br>        android:layout_width=&quot;match_parent&quot;<br>        android:layout_height=&quot;match_parent&quot;<br>        android:background=&quot;@android:color/darker_gray&quot;<br>        app:behavior_hideable=&quot;true&quot;<br>        app:behavior_peekHeight=&quot;56dp&quot;<br>        app:layoutDescription=&quot;@xml/activity_main_scene&quot;<br>        app:layout_behavior=&quot;com.google.android.material.bottomsheet.BottomSheetBehavior&quot;&gt;<br><br>        &lt;!--  Add a button to the layout which will be sticky unless the sheet is hidden --&gt;<br><br>        &lt;Button<br>            android:id=&quot;@+id/button_sticky&quot;<br>            android:layout_width=&quot;0dp&quot;<br>            android:layout_height=&quot;0dp&quot;<br>            android:text=&quot;My Sticky Button&quot; /&gt;<br><br>    &lt;/androidx.constraintlayout.motion.widget.MotionLayout&gt;<br><br>&lt;/androidx.coordinatorlayout.widget.CoordinatorLayout&gt;</pre><p>The first thing we’ve done above is set the root layout to be a <a href="https://developer.android.com/reference/androidx/coordinatorlayout/widget/CoordinatorLayout">CoordinatorLayout</a>, this is required so a view with a <a href="https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior">BottomSheetBehaviour</a> inside acts correctly as a bottom sheet.</p><p>Then we add a MotionLayout as the actual bottom sheet, giving it a BottomSheetBehaviour, with a peekHeight of 56 and make it hidable. Note that if you add this yourself without adding layoutDescription, you’ll get an error that a layoutDescription is needed. Android Studio will create this for you if you use the quick fix shortcut, which is awesome.</p><p>Finally, we add a Button inside the MotionLayout which is what will be sticky. This could be any UI you want, but in this case we’ll just use a Button as an example.</p><blockquote>NOTE: Even though MotionLayout is a subclass of ConstraintLayout, we haven’t provided any constraints, that’s because it all happens inside the generated activity_main_scene.xml file.</blockquote><h4>Setting the constraints</h4><p>If we open up the layout description file that the MotionLayout references (in this case, activity_main_scene.xml), we can update it so that it has the constraints for how we want the Button to be when the bottom sheet is collapsed or expanded:</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;<br>&lt;MotionScene xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;<br>    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;&gt;<br><br>    &lt;!-- Indicates the start and end states of the transition --&gt;<br><br>    &lt;Transition<br>        app:constraintSetEnd=&quot;@id/end&quot;<br>        app:constraintSetStart=&quot;@id/start&quot; /&gt;<br><br>    &lt;!-- The actual start state of the transition --&gt;<br><br>    &lt;ConstraintSet android:id=&quot;@+id/start&quot;&gt;<br>        &lt;Constraint<br>            android:id=&quot;@+id/button_sticky&quot;<br>            android:layout_width=&quot;match_parent&quot;<br>            android:layout_height=&quot;56dp&quot;<br>            app:layout_constraintTop_toTopOf=&quot;parent&quot; /&gt;<br>    &lt;/ConstraintSet&gt;<br><br>    &lt;!-- The actual end state of the transition --&gt;<br><br>    &lt;ConstraintSet android:id=&quot;@+id/end&quot;&gt;<br>        &lt;Constraint<br>            android:id=&quot;@id/button_sticky&quot;<br>            android:layout_width=&quot;match_parent&quot;<br>            android:layout_height=&quot;56dp&quot;<br>            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; /&gt;<br>    &lt;/ConstraintSet&gt;<br>&lt;/MotionScene&gt;</pre><p>The key parts to note here are the start and end ConstraintSets. Traditionally, these are used to indicate the constraints of views at the start and end of a transition, which you can animate between. We’re going to use these two states to keep the Button stuck to the bottom of the bottom sheet instead!</p><p>In our case the start state is equivalent to our bottom sheet’s <em>collapsed</em> state, and the end state is the <em>expanded</em> state. So we’re saying, when collapsed, pin the button to the top of the sheet, and when expanded pin to the bottom.</p><p>We also need to set the height and width values we want. I tried setting this just in the activity_main.xml file but it didn’t work, so we’ll just add it twice here. We’ll match the peekHeight of the sheet with a value of 56dp, and let it fill the width of the sheet.</p><h4>Make it stick!</h4><p>If you run the app now, it still won’t stick. We need to hook into the expanding and collapsing of the bottom sheet so that we can update our MotionLayout’s <a href="https://developer.android.com/reference/androidx/constraintlayout/motion/widget/MotionLayout#setProgress(float)">progress</a>, which is what gives it the effect of being pinned to the bottom of the sheet.</p><p>We do this in code, so we’ll add this code to our MainActivity.kt file:</p><pre>class MainActivity : AppCompatActivity() {<br>    override fun onCreate(savedInstanceState: Bundle?) {<br>        super.onCreate(savedInstanceState)<br>        setContentView(R.layout.<em>activity_main</em>)<br>        <br>        // Get a reference to the MotionLayout, which is acting as our bottom sheet<br>        val motionLayout = findViewById&lt;MotionLayout&gt;(R.id.<em>bottom_sheet</em>)<br>        <br>        // Get a reference to the layout params<br>        val layoutParams = motionLayout.<em>layoutParams </em>as CoordinatorLayout.LayoutParams<br>        <br>        // Get a reference to the BottomSheetBehaviour<br>        val bottomSheetBehavior = layoutParams.<em>behavior </em>as BottomSheetBehavior<br>        <br>        // Add a callback to the bottom sheet so we can get the slide offset<br>        bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {<br>            override fun onSlide(bottomSheet: View, slideOffset: Float) {<br>                // When the slide offset changes, set it as the progress of the motion layout.<br>                // This &quot;transitions&quot; between the start and end sets of constraints as the user slides the sheet.<br>                motionLayout.<em>progress </em>= slideOffset<br>            }<br><br>            override fun onStateChanged(bottomSheet: View, newState: Int) {}<br>        })<br>    }<br>}</pre><p>Essentially what the above code is doing is adding a callback to the BottomSheetBehaviour we set in the layout file, and whenever the slideOffset changes (as the user slides the sheet), we set that as the progress of the MotionLayout.</p><p>Since the slideOffset can be between -1 and 1 (0–1 between collapsed and expanded, -1–0 between hidden and collapsed), and MotionLayout accepts values between 0 and 1, as the user expands and collapses the sheet it perfectly transitions between the ConstraintSets we set earlier to give it the appearance of being stuck to the bottom of the sheet.</p><p>Since the slideOffset when hiding is between -1 and 0, MotionLayout ignores that value so it doesn’t try to transition the constraints, making the button appear no longer stuck and hides as the sheet hides.</p><h4>Final thoughts</h4><p>There are other ways of achieving this, like setting offsets manually on views but this feels extremely convenient to me, and as mentioned earlier this paves the way for more complicated UI that can transition as the user expands and collapses the sheet, something that would get very messy if we had to handle all the offsets ourselves.</p><p>If you want to follow along with my journey into Android dev, follow me here or on <a href="https://twitter.com/kanecheshire">Twitter</a> and I’ll keep sharing what I learn, as I learn it!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3d65ea1d20dc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift Package Manager is a security risk]]></title>
            <link>https://medium.com/@KaneCheshire/swift-package-manager-is-a-security-risk-4d13f3a7bc3b?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/4d13f3a7bc3b</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[swift-package-manager]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Tue, 04 Aug 2020 19:17:03 GMT</pubDate>
            <atom:updated>2020-08-05T09:42:23.828Z</atom:updated>
            <content:encoded><![CDATA[<h3>Swift Package Manager is a potential security risk</h3><p>Let me start off by saying I absolutely love Swift Package Manager and I think it’s the future of dependency management on iOS, so-much-so <a href="https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-12-and-swift-package-manager-a84aedace575">I’ve written posts on what we can do with it</a>.</p><p>But I also want to use this opportunity to highlight a potential risk with using it that I became aware of today. I initially thought there was no issue tracker for Swift Package Manager since there isn’t one in the GitHub repo, but I’ve since reported this issue on the Swift bug tracking Jira instance (<a href="https://bugs.swift.org/browse/SR-13346">SR-13346</a>).</p><p>I’ve found a way to run <em>any code I want</em> when you use one of my Swift packages (providing you don’t check the Package.swift file before hand), and it’s a <em>lot</em> simpler than you might think. Let me show you how.</p><h4>The hack</h4><p>It’s a very, very simple hack, making use of anonymous closures to lazily load the Package instance defined in the Package.swift file for a package.</p><blockquote><strong>UPDATE:</strong> After writing this post and filing a bug with the Swift team I realised even this is more complicated that it needs to be. You can simply create a function that returns anything that the Package instance needs (like a string for the name) and execute any other code you want before returning.</blockquote><p>First, let’s look at a normal, simple Package.swift file that gets generated when you run swift package generate:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ksp09J_b9xgVQEjjZLvpkg.png" /></figure><p>When you add this package as a dependency, Swift Package Manager does some magic by looking for the package instance in this file.</p><p>Since this file is just a regular Swift file, we can write any Swift code we want in here, including tricking Swift Package Manager to call a function whenever the package instance is referenced:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E7zGQMU1kQGR6ete2jENZQ.png" /></figure><p>The code above has hardly been changed, but can now be used to run <em>any code</em> we want in doSomething(). Let’s add some code to doSomething that makes your Mac speak out loud (yes really!):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*06wV8UYb7fF3xO5PS9sE-w.png" /></figure><p>In the above code, we’ve updated doSomething so it now runs an executable file called say which speaks out any words you give it as an argument (included in every Mac by default).</p><p>Notice how we’re able to literally execute a programme that is stored in usr/bin. To do this we have to use a Process instance, which is part of AppKit, which we have no problems importing into our Package.swift file, because it’s just Swift code running on a Mac.</p><p>If you add our package as a dependency to another package, or as a dependency in an Xcode project, you’ll hear your Mac say “hello world” whenever the package is resolved. In fact, you only have to save the Package.swift file to test it and it’ll speak.</p><p>This gets more worrying when you add this package as a remote dependency in Xcode (11 or 12), because the code runs as soon as you add it as a dependency:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TtmHZsjj1QKJnrD47V3z8A.png" /></figure><p>By the time you get to that screenshot above in Xcode 11 or 12, the function has already been called and your Mac has said “hello world” out loud.</p><h4>Going further</h4><p>Just being able to import AppKit opens up the possibility of so many things, both malicious and not. As an example, with AppKit you can get a list of running apps, terminate them and launch new processes with <a href="https://developer.apple.com/documentation/appkit/nsworkspace">NSWorkspace</a>.</p><p>We can import other macOS frameworks too, like <a href="https://developer.apple.com/documentation/collaboration">Collaboration</a>, which lets us get information like the<a href="https://developer.apple.com/documentation/collaboration/cbidentity/1423863-fullname"> full name</a> of the current user, and more alarmingly, <a href="https://developer.apple.com/documentation/collaboration/cbuseridentity/1423892-authenticate">test to see if a password is the correct password</a>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4E7Ky6tQiZf8jmCYqmjTXQ.png" /></figure><p>If “notmypassword” happens to be your actual login password for your Mac, the above code will speak out:</p><blockquote><strong>“Hello [your name], notmypassword is your password”</strong></blockquote><p>Even without importing AppKit or any of the other macOS frameworks, we can import Foundation which allows us to make any network requests we want:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ykh3ioy0xziRmS_8D2RaOQ.png" /></figure><p>The above code uses a DispatchGroup to make the thread wait until the network call has completed. This network call could be used to download any data from any site, and upload any data anywhere.</p><p>If that wasn’t enough, since you can access FileManager from Foundation, you can also write any data to disk, as well as read directly from the filesystem, or delete files. In theory, you could delete the entire user directory (although I was too chicken to try!).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sWclBLoRRxEX8mczRf63oQ.png" /></figure><p>The above code iterates through the entire filesystem, logging each item to the console. Thankfully in Catalina you do have to give Xcode permission to access some directories, but that just confirms that you’ll be able to run code in any privileged way that Xcode does. I’m also subconciously trained to just accept any permissions requests that Xcode throws up at me.</p><p>These are just a few examples off the top of my head of what we can do with this, I’m sure there are plenty more that cleverer people can think of.</p><h4>Mitigations</h4><p>What can you do to protect yourself from people who want to abuse this vulnerability?</p><p>Well, unfortunately you can’t entirely, but you can help protect yourself by checking each 3rd party Package.swift file before using it, and make sure you target a specific version in a remote repo rather than always resolving the latest version of a branch. Remember though there’s nothing stopping someone from changing the code that a tag in a remote repo references.</p><p>Additionally, you should only use packages from developers you trust. Unfortunately this could be an unfair disadvantage for new developers with something cool they want to share via Swift Package Manager, and in any case there’s still a risk (albeit small) reputable developers could have their repositories compromised.</p><p>Hopefully, GitHub will be able to add some vulnerability checks for Swift packages like they do with other language dependencies in the future, and of course hopefully the Swift developers find a way to plug this properly without impacting the usefulness of either Swift Package Manager or system frameworks.</p><p>In the interests of fairness, I should also point out that <a href="https://guides.cocoapods.org/syntax/podspec.html#script_phases">Cocoapods has a way of running scripts as the framework is being built</a>, however they at least choose to log warnings to developers so it’s not completely silent. And they expose it as an official feature so people are more aware of it.</p><p>You should also make sure you’re not storing anything sensitive on disk outside of the Keychain, that means no storing passwords in unencrypted text files, no leaving private keys or certificates on the desktop etc.</p><p>Additionally, although I was able to write code that retrieves private keys from the keychain (or references to keys, more specifically), I wasn’t able to actually use the key to sign data without a permissions prompt coming up:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0lmaPMhmjQg9YB4cKggfbA.png" /></figure><p>This is why it’s important not to blindly allow permissions for things that pop up, even if they seem like they’re coming from the system. For example, using some keychain code I was able to get this popup to appear while trying to use private keys:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nhnlG4BpCy_ABi-yirvOmA.png" /></figure><p>That one is particularly worrying because it doesn’t mention my package name anywhere, and since it’s saying macOS wants to make changes I would be tempted to allow it if I didn’t know it was my code that caused it. I don’t know what entering my username and password does in this case, because again I was too chicken to try (maybe I can set up a demo machine so I can properly try this stuff without worrying!).</p><h4>It’s not all bad</h4><p>If you’ve read this far you might be worried (and rightly so), but it’s also worth pointing out that although this can be used for evil, it can also be used for good.</p><p>This sort of thing could enable code generation (which is why I thought of this in the first place), or providing some required automatic setup for users of libraries that have a difficult setup process (like adding build phase scripts for Firebase).</p><p>Sadly, we live in a world where bad actors ruin things and That’s Why We Can’t Have Nice Things™️.</p><h4>How can the Swift team fix it?</h4><p>I’m honestly not sure the best way for the team to fix it, if Swift code is going to be allowed in full then this will always happen. Perhaps disallowing imports or functions when parsing the Package.swift file could work.</p><p>I’ve created an <a href="https://github.com/KaneCheshire/maleficent">example repository</a> which you can check out if you want to see it for real.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4d13f3a7bc3b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Modern Modular Apps With Xcode 12 and Swift Package Manager]]></title>
            <link>https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-12-and-swift-package-manager-a84aedace575?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/a84aedace575</guid>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[swift-package-manager]]></category>
            <category><![CDATA[engineering]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Thu, 30 Jul 2020 09:34:56 GMT</pubDate>
            <atom:updated>2020-07-30T09:34:56.843Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qRy2Zv-G1V876V7fGyG7CA.jpeg" /></figure><p>Last year, after Apple released the first beta of Xcode 11 with native support for Swift Package Manager (SPM) built in, <a href="https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-11-and-swift-package-manager-6b4afa0125be">I wrote a post</a> on how we can leverage this to build modular apps with Swift Packages.</p><p>In it, I touted that it would make it possible to ditch Cocoapods as a dependency manager, but what we ran into quickly was a limitation with being unable to include resources in a Package, like colour assets, fonts, storyboards/xibs etc.</p><p>Thankfully, Xcode 12 includes the latest version of SPM which now allows Packages to include <em>any</em> resources, by including a new static property on Bundle named .module. This Bundle instance references the current<em> module</em>, rather than just being able to reference the current <em>target</em>.</p><p>In this post, we’ll update our project from last year to include some assets which we can expose from the Package for use in any other module or target!</p><h4>Step 1</h4><p>To continue, first <a href="https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-11-and-swift-package-manager-6b4afa0125be">follow the steps in last year’s post</a>, then come back here and we’ll carry on from there.</p><blockquote><em>NOTE: You’ll need to use Xcode 12 instead of Xcode 11. Since you’ll be using Xcode 12 and a new version of SPM, you may encounter some slight differences in how to set up a module from last year’s post.</em></blockquote><blockquote><em>Notably, you’ll have to provide a</em><strong><em> package name</em></strong><em> as well as a product name when declaring dependencies in FantasticFeature. You can just use the same value for both.</em></blockquote><h4>Step 2</h4><p>Welcome back! If you’ve followed along and got the project building from last year, you should have:</p><ul><li>A workspace named <strong>AmazingApp</strong>;</li><li>A project also named <strong>AmazingApp</strong>;</li><li>A Swift Package representing a feature module called <strong>FantasticFeature</strong>;</li><li>Another Swift Package representing a shared module called <strong>Common</strong></li></ul><p>Make sure you’ve opened the workspace (not the project), and in the <strong>Common</strong> module we’ll add a new asset catalogue for our colours that we want to use across our app.</p><p>In the workspace, create a new file (command + N) in [<strong>Common</strong>] ➡ [<strong>Sources</strong>] ➡ [<strong>Common</strong>,] choose <strong>Asset Catalogue</strong> and click <strong>Next</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7l01f3xa0NIP-AnlK3tl_A.png" /></figure><p>Since you can have multiple asset catalogues in any module, lets call this one <strong>Colors.xcassets</strong> in case we add others for images etc in the future.</p><h4>Step 3</h4><p>You should now have an empty asset catalogue called <strong>Colors.xcassets</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LjaOQ9HzjPsd-YH6ffbLkg.png" /></figure><p>Let’s add some colours to it! Click the <strong>plus</strong> icon (not the one in the workspace, the one in the catalogue), and then click <strong>Color set</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6LZwd5gC3zjOl0s2KOhjYQ.png" /></figure><p>Name your colour something like primarySurface (which we’ll later expose in code), and then set whatever colour values you want for light and dark appearances:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*y04pi-yx33gp9coYnUqt9Q.png" /></figure><h4>Step 4</h4><p>Now we can expose this in code, so in the <strong>Common</strong> module create a new <strong>Swift file</strong> called <strong>Colors.swift</strong> and create a public extension of UIColor to expose the colours from the catalogue:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0FWSpzWlFeXmqDyzqxt_2Q.png" /></figure><p>You might get the error above about using a UIColor initialiser that is only available in iOS 11, since the <strong>Common</strong> module doesn’t yet declare a specific platform. You can fix this by opening up the <strong>Package.swift</strong> file in the <strong>Common</strong> module and explicitly setting the platform to iOS 11 or newer:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FKe1LEcuhLsGHG0AUY1iDA.png" /></figure><p>Looking back at <strong>Colors.swift</strong>, you can see we’re creating a static constant on UIColor (line 5) named primarySurface, which creates a UIColor by name from the <strong>Colors.xcassets</strong> catalogue.</p><p>The most important part of that code is the .module which is a static constant on Bundle representing our module.</p><p>In effect, that line of code is saying “create a UIColor from a colour named &quot;primarySurface&quot;, defined in an asset catalogue in this module and store it in a static constant also called primarySurface“.</p><h4>Step 5</h4><p>Now we’ve exposed our colour in code, we can use it in code in this or other modules. As an example, let’s use it to change the background colour of the view controller that is shown when we run the app in the simulator.</p><p>In <strong>ViewController.swift</strong>, in the viewDidLoad function, set the view’s backgroundColor to our newly exposed primarySurface colour:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Xl499fPW9OghFKRJ85TUrA.png" /></figure><p>You’ll need to import Common at the top of the file, and once you do that you can run the app and the view’s background colour will be whatever colour you chose in Colors.xcassets:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BUdcpcPGfDz5mGllq9ulYg.png" /></figure><p>As an added bonus, because we defined both a light and dark variant of that colour, the system automatically knows how to select and change to the right one. You can test this by clicking the <strong>Environment Overrides</strong> button in Xcode and changing the <strong>Appearance</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0SlvLfPRloUor41ep7Uswg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jcTfa0HOBrCeQ1fHfUFKXA.png" /></figure><p>Unfortunately, you can’t set the colour directly in a Storyboard or Nib unless the colour is defined in the same module as the Storyboard/Nib, but that’s the same when using regular Xcode projects as modules instead of Packages.</p><h4>Final thoughts</h4><p>I love how quick it is to create a new module using SPM, and although this example is fairly simple and just exposing a colour, that is only possible because a Package can now include and references resources just like legacy Xcode projects.</p><p>In a matter of moments, you can create a new module, declare its dependencies which Xcode will automatically resolve for you, and now include Storyboards, assets, fonts and anything else you want.</p><p>There are still some downsides to using SPM, like clearing derived data requiring your packages be re-resolved (which also means cloning any remote repos like Alamofire again). But personally, I would take these small annoyances over the pain of creating and managing Xcode projects as modules.</p><p>SPM is fast becoming the only dependency manager you’ll need for developing Swift apps and libraries, without the need to manually run any commands in Terminal or manage a bunch of Xcode projects in a workspace or worrying about dealing with Xcode project file conflicts when creating a pull request.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a84aedace575" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-12-and-swift-package-manager-a84aedace575">Modern Modular Apps With Xcode 12 and Swift Package Manager</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[5 things every iOS developer learning Android should know]]></title>
            <link>https://medium.com/kinandcartacreated/5-things-every-ios-developer-learning-android-should-know-f1127a07f240?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/f1127a07f240</guid>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Wed, 27 May 2020 20:42:48 GMT</pubDate>
            <atom:updated>2020-05-27T20:42:48.590Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*oYVaRmqDYQ_PV5K9" /><figcaption>Photo by <a href="https://unsplash.com/@grohsfabian?utm_source=medium&amp;utm_medium=referral">Fabian Grohs</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>I recently started my journey into Android development after creating iOS apps for 5 years, and there are a few things I wish I knew that tripped me up at the start.</p><p>In this post, I’ll go over 5 of them, so if you’re learning (or thinking about learning) Android as well, I hope this post helps you!</p><h4>1. Views &amp; ViewGroups</h4><p>On iOS, views are represented as <a href="https://developer.apple.com/documentation/uikit/uiview">UIView</a> subclasses, similarly on Android views are represented as <a href="https://developer.android.com/reference/android/view/View">View</a> subclasses.</p><p>On iOS, you can add a UIView as a subview of any other UIView. On Android, <strong>you can only add a </strong><strong>View as a subview</strong> (technically, child view) <strong>inside a </strong><a href="https://developer.android.com/reference/android/view/ViewGroup"><strong>ViewGroup</strong></a> (even though ViewGroup is actually a subclass of View).</p><p>A ViewGroup is typically something like a <a href="https://developer.android.com/reference/android/widget/LinearLayout">LinearLayout</a>, <a href="https://developer.android.com/reference/androidx/constraintlayout/widget/ConstraintLayout">ConstraintLayout</a> etc, and is designed to display multiple views (hence “group”). You can add other ViewGroups to a ViewGroup, which is how you build up a layout or hierarchy.</p><h4>2. Activities &amp; Fragments</h4><p>On iOS you use a <a href="https://developer.apple.com/documentation/uikit/uiviewcontroller">UIViewController</a> to represent a whole screen, or part of a screen by embedding a child UIViewController into a UIViewController&#39;s root view.</p><p>On Android, you can use an <a href="https://developer.android.com/reference/android/app/Activity">Activity</a> to represent a whole screen, or you can embed one or more <a href="https://developer.android.com/reference/android/support/v4/app/Fragment.html">Fragment</a>s inside an Activity to represent an entire screen or parts of a screen (hence, fragment).</p><p>Unlike a UIViewController, an Activity always uses the full screen. Since you can transition multiple full-screen Fragments in an Activity, it&#39;s completely possible to have a single Activity for your entire Android app.</p><h4>3. The Lifecycle</h4><p>On iOS, you typically have an app lifecycle like this:</p><pre>- App launched &lt;--------------|<br>- App enters foreground &lt;--|  |<br>- App becomes active       |  |<br>- App resigns active       |  |<br>- App enters background    |  |<br>- App suspended &gt;----------|  |<br>- App terminates &gt;------------|</pre><p>And then during the app’s life you can also have lifecycles of individual view controllers:</p><pre>- init<br>- VC view did load<br>- VC will appear &lt;----|<br>- VC did appear       |<br>- VC will disappear   |<br>- VC did disappear &gt;--|<br>- deinit</pre><p>An Android app has its own lifecycle too, but it’s mostly linked to the current <a href="https://developer.android.com/guide/components/activities/activity-lifecycle">activity</a> or <a href="https://developer.android.com/guide/components/fragments#Creating">fragment</a> (this is a simplified version of both, check out the links for a detailed explanation):</p><pre>- onCreate<br>- onStart &lt;---------|<br>  (visible)         |<br>- onResume &lt;----|   |<br>  (interactive) |   |<br>- onPause &gt;-----|   |<br>  (not interactive) |<br>- onStop &gt;----------| <br>  (not visible)<br>- onDestroy</pre><p>Additionally, the app itself has a couple of lifecycle events:</p><pre>- onCreate<br>- onTerminate</pre><p>Generally, you’ll just care about the lifecycle of the current activity or fragment.</p><p>As a user navigates around your Android app (or the system), any of these events can happen.</p><p>An activity (or fragment) is visible when it’s started and interactive when resumed. It can be paused if it’s obscured by something else like the <a href="https://developer.android.com/guide/topics/ui/notifiers/notifications">Notification Drawer</a>, or if the app is in split screen and no longer the “active” app.</p><p>The most important thing to know is that an activity <strong>can be recreated at any time </strong>by the system, which means that you cannot rely on state stored inside your activity (or any fragments it contains), since it will be a new instance! An example of when this can happen is when you rotate the device.</p><p>You can use <a href="https://developer.android.com/topic/libraries/architecture/viewmodel">ViewModel</a>s in your activities and fragments to hold state that persists between instances as needed. The system will manage whether to create a new view model for you, providing you <a href="https://developer.android.com/topic/libraries/architecture/viewmodel#lifecycle">create the ViewModel correctly</a>.</p><p>It’s also worth mentioning that onDestroy and onTerminate aren’t guaranteed to be called (same as how applicationWillTerminate is not guaranteed to be called on iOS).</p><h4>4. Contexts</h4><p>In my opinion, this is the biggest difference between building an iOS app and an Android app.</p><p>On Android, you’ll often find many classes and functions requiring you to pass in this mystical object called a <a href="https://developer.android.com/reference/android/content/Context">Context</a>.</p><p>A Context is really just a class that provides access to app resources (like strings and images), system services (like <a href="https://developer.android.com/reference/android/bluetooth/BluetoothAdapter">Bluetooth adapters</a> and <a href="https://developer.android.com/reference/android/app/NotificationManager">notification managers</a>), send <a href="https://developer.android.com/reference/android/content/Intent">Intent</a>s and information about the current environment.</p><p>Typically, you can just pass a reference to the current activity as the context, (which you can access from within fragments inside activities), and if you really have to, you can also use the application context.</p><p>Since you will find yourself passing around contexts quite often, it can be tempting to store a reference to a context in your custom classes and view models. It’s best to avoid this as much as possible, since it can cause memory leaks (for example, if the activity passed as the context was destroyed by the system, your class would still hold a permanent reference to it).</p><p>The concept of a context doesn’t really exist on iOS, although <a href="https://developer.apple.com/documentation/uikit/uitraitcollection">UITraitCollection</a>s are similar in that they provide information about the current environment, and can be accessed through UIViewController or <a href="https://developer.apple.com/documentation/uikit/uiscreen">UIScreen</a> instances.</p><h4>5. Backwards compatibility</h4><p>I <em>was</em> going to include memory management as number 5, but given that’s more language specific than platform specific I changed my mind and went with backwards compatibility as the final thing you should know.</p><p>When you create a new iOS app, the general consensus is you should support the last two major versions of iOS, because the iOS platform has a great track record of getting users onto the latest versions of iOS, and Apple keep releasing new versions of iOS for older iOS devices.</p><p>When creating an Android app, you’ll straight away notice that when creating the app in Android Studio, it’ll ask you what versions of Android you want to target. As you change your selection, Android Studio will show you an estimate of how many devices that can be installed on.</p><p>If you choose the last two major versions like you would for iOS, you’ll likely be disappointed by the number Android Studio estimates.</p><figure><img alt="Screenshot of a breakdown of app reach per Android OS version, according to Android Studio" src="https://cdn-images-1.medium.com/max/1024/1*kQGt8C1dIaz7aoF8l0eLDQ.png" /></figure><p>It’s not as bad as you might think though, because of a difference between the way iOS and Android handle frameworks and backwards compatibility.</p><p>On iOS, all frameworks are bundled with the system, which means that you <em>need</em> people to be on the latest versions of iOS to use some APIs. On Android, it’s different. Some frameworks are added as dependencies to your app as needed, and Google put a lot of effort into creating support/compatibility frameworks which make APIs backwards compatible, like <a href="https://developer.android.com/jetpack/androidx">AndroidX</a>, part of the <a href="https://developer.android.com/jetpack">Android Jetpack libraries</a>.</p><p>During development of your Android app, and while looking at tutorials, you’ll see a lot of *Compat references, like <a href="https://developer.android.com/reference/androidx/appcompat/widget/SwitchCompat">SwitchCompat</a>, and these provide backwards compatibility onto versions of Android that don’t support the standard versions like <a href="https://developer.android.com/reference/android/widget/Switch">Switch</a>.</p><p>Even with AndroidX, you’ll still want to balance supporting very old versions with how much testing you’re willing to carry out. Since there’s such a huge array of Android devices, the older you go, the harder it is to test your app well. Personally, I’ve added support to API level 26 (Android 8.0/Oreo), which means my app will run on roughly 61% of devices.</p><p>I can choose API level 26 keeping my user base in mind, since I know most people who will use my app (which connects to another device) will likely have newer phones.</p><h4>What next?</h4><p>Now that you know these 5 important things, there’s nothing left to do but start coding!</p><p>Download <a href="https://developer.android.com/studio">Android Studio</a> (it’s free, and you don’t even need to create an account to use it!), <a href="https://developer.android.com/training/basics/firstapp/creating-project">create a new project</a> and get going. Feel free to <a href="https://twitter.com/kanecheshire">reach out to me</a> if you have any questions. I’m still learning too, so we can learn together!</p><p>If you want to learn more about memory management on Android, <a href="https://blog.indoorway.com/swift-vs-kotlin-the-differences-in-memory-management-860828edf8">this post</a> is a great primer.</p><p>As with anything, it’ll feel alien at first, but in no time it’ll all start to click together and your biggest issue will be having to remember when to type <a href="https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html#ID310">let</a> or <a href="https://kotlinlang.org/docs/tutorials/kotlin-for-py/declaring-variables.html#read-only-variables">val</a> depending on what platform you’re developing for.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f1127a07f240" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/5-things-every-ios-developer-learning-android-should-know-f1127a07f240">5 things every iOS developer learning Android should know</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[Why bespoke Contact Tracing apps don’t work so well on iOS]]></title>
            <link>https://medium.com/kinandcartacreated/why-bespoke-contact-tracing-apps-dont-work-so-well-on-ios-df0dabd95d42?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/df0dabd95d42</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[covid19]]></category>
            <category><![CDATA[contact-tracing]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Tue, 19 May 2020 13:00:36 GMT</pubDate>
            <atom:updated>2020-05-19T13:27:50.474Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*e7kZQ75dju0oaiAq" /><figcaption>Photo by <a href="https://unsplash.com/@nasa?utm_source=medium&amp;utm_medium=referral">NASA</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>While Apple and Google work on a new <a href="https://www.apple.com/covid19/contacttracing">cross-platform contact tracing API</a> to help tackle the COVID-19 pandemic, we’re starting to see some countries release bespoke apps built using just the existing Bluetooth APIs on each platform.</p><p>What we’re quickly seeing in the media about these solutions is that the iOS app has some limitations while in the background (i.e. not the visible and active app), and as a result the creators of these apps are often recommending people leave the iOS app in the foreground, or that they work better if Android devices are nearby.</p><blockquote><strong>IMPORTANT:</strong> This post is not designed to call out any specific implementation by any country, nor should you as a reader be worried about downloading any of them! Although the general consensus is it’s better if countries used the Apple|Google framework, we should still use what is currently available until something potentially better is available.</blockquote><p>What we’re not really seeing in the media is a high level technical explanation of exactly <em>why</em> bespoke iOS Contact Tracing apps seem to be so ineffective while running in the background, and why Android doesn’t have the same limitations. I aim to cover exactly that in this post at a high level. You do not need to be a developer to read this post!</p><blockquote><strong>TL;DR:</strong> It’s because of the way iOS restricts developers running apps in the background to protect privacy and battery life, which is very different from how Android allows apps to run in the background.</blockquote><blockquote>I really recommend you read the whole post though, you’ll learn lots about how both iOS and Android work, and more specifics about why this means bespoke Contact Tracing apps have issues on iOS, and a whole bunch more interesting stuff!</blockquote><h4>What is a Contact Tracing app</h4><p>Before I go any further, you might be wondering what a Contact Tracing app is actually for. In simple terms, it is designed to keep track of people you have been in close proximity to, and if any of those people are diagnosed with COVID-19, you can be notified so you can self-isolate or get tested, and other people you’ve been close to can do the same. For that to be effective, it needs to be installed on a lot of devices!</p><p>Contact Tracing apps on iOS and Android use something called <a href="https://en.wikipedia.org/wiki/Bluetooth_Low_Energy">Bluetooth Low Energy (LE)</a>, which I’ll just call Bluetooth throughout this post. I’m writing this post as someone who’s developed and released two iOS apps that use Bluetooth while in the background reliably, and I’ve ported one of those apps to Android which has taught me a great deal about the differences between the two platforms when it comes to running the code reliably while the app is not the foreground (visible) app.</p><blockquote><strong>COMMENT: </strong>I can tell you straight off the bat, lots of people don’t like leaving apps running. Since my users don’t even like leaving my apps running in the iOS App Switcher, they definitely would not use my app if it meant leaving the app running in the foreground (so the app is visible) at all times!</blockquote><p>Now we know what a Contact Tracing app is, let’s talk about exactly <em>why</em> the creators of these apps are recommending that people leave their iOS apps running in the foreground to make them more reliable, and why it’s not a problem on Android.</p><h4>The iOS App Lifecycle</h4><p>Let’s start with the basics, since understanding the general lifecycle of an iOS app is important before continuing.</p><p>When we create an iOS app, by default it cannot run in the background at all, <strong>even when it’s showing in the iOS </strong><a href="https://support.apple.com/en-gb/HT202070"><strong>App Switcher</strong></a>. When you leave the app to go to the Home Screen, or a different app, the system “freezes” the app after a few seconds and puts it into what’s called a “<a href="https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle">suspended</a>” state. At this point, the app is no longer in the foreground, and no longer the active app.</p><blockquote><strong>NOTE:</strong> It’s important to understand, your app isn’t using any battery while in the suspended state. Even though it’s showing in the App Switcher, it’s not doing anything!</blockquote><p>While in the suspended state, if another app (or iOS itself!) needs more memory (RAM) then the suspended app can be terminated. As a user, you’d still see the app in the App Switcher, but it’s <strong>just an </strong><a href="https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background#3222195"><strong>image</strong></a><strong> of the last state of the UI</strong> before it was suspended.</p><p>Of course, things have changed since <a href="https://en.wikipedia.org/wiki/IPhone_OS_1">iPhone OS 1.0</a> and iOS apps can now perform certain tasks while in the background, including continuing to play audio like Spotify, track your location (with permission) like Strava, and also use Bluetooth (again, with permission), like Contact Tracing apps.</p><p>For this to happen, when we’re making our iOS app we have to declare to the system (iOS) that our app wants to do certain tasks while in the background. We declare this by enabling one or more “<a href="https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/about_the_background_execution_sequence">background modes</a>”.</p><p>Once we enable a specific background mode, we can then use special APIs that allow these tasks to be carried out. Each background mode has different APIs and rules, and has a different impact on your device’s battery life. For this post, all we care about are the Bluetooth ones.</p><h4>The Bluetooth LE background modes</h4><p>To use Bluetooth in the background on iOS, we need to enable one (or both) of two different background modes for our app (more on the difference between them later).</p><p>Once we’ve enabled the right background mode(s), our app can continue to use the relevant Bluetooth APIs while not the active app, <strong>however there are some really nuanced rules</strong> around how this works and what we’re able to do.</p><p>But, before I can go into that, I need to explain to you the two different types of Bluetooth APIs that an iOS app can use! In Bluetooth LE, there is a concept of a <a href="https://developer.apple.com/documentation/corebluetooth/cbcentral">Central</a> and a <a href="https://developer.apple.com/documentation/corebluetooth/cbperipheral">Peripheral</a>.</p><p>A <strong>Central</strong> is typically something like a phone or laptop. You can think of this as the <strong>client</strong>.</p><p>A <strong>Peripheral</strong> is typically something like a heart rate monitor, or some device like an electric skateboard. You can think of this as the <strong>server</strong>.</p><p>The Peripheral (or server) has data, and the Central (or client) wants to read that data. The Peripheral <strong>advertises</strong> itself, and the Central can <strong>scan</strong> for it, connect to it once it finds it, and read some data. The concept of advertising and scanning is important to remember for later in this post.</p><p>iOS and Android apps can act as <strong>both</strong> the Central and the Peripheral at the same time, which makes them (almost) perfect for use as a Contact Tracing app.</p><h4>How Contact Tracing apps use Bluetooth LE</h4><p>At an extremely high level, the way a Contact Tracing app could work, is every iOS and Android device with the app installed allows the app to act as both a Central and a Peripheral.</p><p>This means each device simultaneously <strong>advertises</strong> itself to other devices to be discovered and connected to, as well as <strong>scans</strong> for other nearby devices to discover and connect to.</p><p>When they discover each other, they can connect, transfer a small amount of data to identify that device, then use that information to be able to say those two devices have been near each other.</p><blockquote><strong>NOTE:</strong> I’m not going to go into specifics about privacy or cryptography here, that’s a whole different topic!</blockquote><p>For it to work well, this needs to happen regardless of whether a user is currently using your app in the foreground, whether they have the phone locked, or whether they’re just using another app.</p><p>For that to happen in our iOS app, we’d need to enable the two background modes I mentioned earlier that allow the app to continue to use Bluetooth APIs as both a Central and a Peripheral while no longer the active app.</p><p>Once we have those enabled, if we start advertising as a Peripheral, and scanning for other Peripherals as a Central, that will <strong>continue to happen when our app is no longer the active app</strong> and our app is in the background.</p><p>Even though we’ve now enabled the background modes and are advertising and scanning, our app will <strong>still enter the suspended state</strong> after a few seconds of being in the background. <strong>The system itself actually takes over the scanning and advertising</strong>, while our app is completely frozen.</p><blockquote><strong>NOTE: </strong>This is one of the reasons Bluetooth LE apps use such little power on your iPhone!</blockquote><p>Only when a Bluetooth event happens (like discovering another Peripheral) will our app get resumed (unsuspended) in the background to handle the event, shortly becoming suspended again after a few seconds.</p><p>The system will carry on doing this for us as long as our app is in the App Switcher (and the iOS device is not restarted), <strong>even if our app is terminated in the background to free up memory for another app </strong>by the system.</p><p>If a Bluetooth event arrives after our app is terminated by the system, <strong>our app is re-created</strong> so we can handle it, and then it will be suspended again.</p><p>This all happens in the background, so to a user it’s seamless and seems as though our app is doing all the work. This is the magic of background execution on iOS.</p><blockquote><strong>IMPORTANT: </strong>Up until iOS 13.4, if we remove our app from the App Switcher, the system will no longer advertise and scan on our behalf, and we’ll have to wait until the app is next launched by the user to start again.</blockquote><blockquote>In iOS 13.4 that behaviour seems to have changed and it will continue to stay connected after removing the app from the App Switcher, but that change is undocumented and shouldn’t be relied on.</blockquote><h4>So what’s the problem?!</h4><p>That all sounds great, right? Looking at the above, it seems like iOS will continue to do the work we need for us to create our bespoke Contact Tracing app!</p><p>So why do the creators of bespoke Contact Tracing apps recommend that people leave the iOS app in the foreground, or do other things to keep the app working reliably?</p><p>Well, remember earlier I said that there are some really nuanced rules around how the iOS Bluetooth background modes work? This is where that comes in.</p><h4>iOS Peripherals in the background</h4><p>Let’s first talk about the <strong>Peripheral background mode</strong>, because this is the main issue.</p><p>When our app is in the background and we want to let the system take over advertising for our app, <strong>it will only allow us to </strong><a href="https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393252-startadvertising"><strong>advertise in a way that lets other iOS devices discover it</strong></a><strong>.</strong></p><p>This means that other Android devices scanning for nearby devices <strong>cannot find an iOS device</strong> while the iOS app is in the background (although there is an <a href="https://github.com/crownstone/bluenet-ios-basic-localization/blob/master/BROADCASTING_AS_BEACON.md#scan-response">undocumented</a> way to do it, it’s never a good idea to rely on undocumented behaviour, especially when it comes to Bluetooth).</p><p>Additionally, I ran a test where I kept an iOS device locked with a simple <a href="https://github.com/theappbusiness/Tracy">Contact Tracing example app</a> running in the background, after 30 minutes I installed the same app onto a different iOS device, and they couldn’t discover each other until I brought the app into the foreground on one of the devices.</p><blockquote><strong>NOTE:</strong> During my testing, I also found occasions as well where an iOS device couldn’t discover another iOS device that was locked, until I just woke the screen while it was still locked. Sometimes that was less than 30 minutes.</blockquote><p>On iOS, Peripheral advertising performance while our app in the background can also be impacted based on whether the iOS device has other apps acting as a Peripheral as well. <strong>iOS decides the performance on our behalf</strong>, and it’s not something we have any control over.</p><h4>iOS Centrals in the background</h4><p>Let’s also talk about the <strong>Central background mode</strong>. While our iOS app is in the background, the system will likely slow down the rate of scanning for nearby devices to save battery.</p><p>Although this isn’t a dealbreaker, it will definitely reduce the usefulness of scanning for nearby Peripherals which may be missed because you walked past someone while it wasn’t actively scanning.</p><h4>Bluetooth LE on Android</h4><p>Now that we’ve learnt the restrictions the iOS system has on developers using Bluetooth while in the background, and why they’re a problem for Contact Tracing apps, we can talk about why these aren’t problems on Android.</p><p>The Android system has a very different approach when it comes to letting apps continue to operate while they’re not the “active” app. Instead of background modes like on iOS, Android uses something called “<a href="https://developer.android.com/guide/components/services">services</a>” to allow us to continue to run code reliably while the app is not the active app.</p><p>Specifically, these are called “<a href="https://developer.android.com/guide/components/services#Foreground">foreground services</a>”, and to use them as developers we <strong>must show a user-visible notification</strong> in the <a href="https://developer.android.com/guide/topics/ui/notifiers/notifications">Notification Drawer</a>.</p><p>The user is <strong>always able to terminate these services</strong> if they wish, although to do so they might need to force-stop the app from within System Settings.</p><p>Unlike an iOS app, an Android app does <strong>not</strong> have to be in the “<a href="https://developer.android.com/guide/components/activities/recents">Recents</a>” app list (the equivalent of the iOS App Switcher) for the service to continue to run.</p><p>When we create a service, we <a href="https://developer.android.com/guide/components/services#Declaring">declare it</a> to the system in our app’s <a href="https://developer.android.com/guide/topics/manifest/manifest-intro">manifest file</a> (a file the system uses to know what your app can do), and then we are free to run whatever code we want in there, potentially indefinitely.</p><p>This makes it perfect for running long-running Bluetooth code, acting both as a Central and a Peripheral, with very few restrictions. Exactly what our Contact Tracing app needs!</p><p>This is why Android Contact Tracing apps aren’t recommended to be kept in the foreground by their creators, because there’s no need.</p><p>Additionally, the Android Bluetooth APIs give us more options for scanning for Peripherals, which allows for an (undocumented) workaround for scanning for iOS Bluetooth apps that are only meant to be discoverable by other iOS Bluetooth apps.</p><blockquote><strong>NOTE:</strong> This workaround is quite technical, and it’s exactly what the smart developers who created the NHSX Contact Tracing Android app <a href="https://github.com/nhsx/COVID-19-app-Android-BETA/blob/43a167f8dba422fd9001b64f9c4fd82275abb1c8/app/src/main/java/uk/nhs/nhsx/sonar/android/app/ble/Scanner.kt#L67">have done</a>.</blockquote><blockquote>It involves scanning for nearby devices with very specific data encoded in an undocumented way on iOS devices. Very clever!</blockquote><p>The tradeoff for this freedom on Android, is that we run the risk of using more battery than is necessary, and the system can start to suggest to our users that our app is using more battery than it thinks we should be. Ultimately though, the Bluetooth code is still running the same as if the app was the active app.</p><p>Also, unlike iOS, you have significantly more control over whether to advertise and scan more aggressively for increased performance, or conservatively to reduce power consumption. This means our Android Contact Tracing app is far more likely to discover passers by in time if we choose to.</p><p>Having worked with Bluetooth on both platforms, I can say there are pros and cons to each.</p><p>iOS is clearly more restrictive, but the API and hardware is more stable, because Apple have full control over it all. Android gives us far more freedom and power, but the API is more difficult to get up and running with, and some older hardware just doesn’t work as well.</p><blockquote><strong>NOTE:</strong> At the time of writing, the <a href="https://developer.android.com/guide/topics/connectivity/bluetooth-le#find">official Android documentation</a> for getting started with Bluetooth LE uses deprecated APIs!</blockquote><p>Ultimately, using the existing Bluetooth APIs available, Android apps are better at performing the role for a Contact Tracing app.</p><h4>How is the Apple|Google cross-platform framework different on iOS?</h4><p>The reason the <a href="https://www.apple.com/covid19/contacttracing">Exposure Notification framework</a> currently being built by Apple and Google is better on iOS than just using the existing <a href="https://developer.apple.com/documentation/corebluetooth">Core Bluetooth</a> APIs is because Apple can avoid the previously mentioned restrictions with apps using Bluetooth in the background.</p><p>Because Apple are making the framework, they can automatically give the Exposure Notification framework priority on the system, ensure that it isn’t abused by developers, and balance power consumption correctly <strong>specifically for Contact Tracing</strong>.</p><h4>Footnote</h4><p>I have validated my claims with online documentation and by writing and testing some <a href="https://github.com/theappbusiness/Tracy">sample code</a> which you are welcome to download and nose about in if you want!</p><p>I’m on <a href="https://twitter.com/kanecheshire">Twitter</a> if you want to ask me any questions about this post, or sample code. Alternatively, you can <a href="https://github.com/theappbusiness/Tracy/issues/new">open an issue on GitHub</a> and as a question there.</p><p>Some useful documentation if you want to read more on the APIs available:</p><ul><li><a href="https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW1#//apple_ref/doc/uid/TP40013257-CH7-SW9">iOS Core Bluetooth Programming Guide</a></li><li><a href="https://developer.apple.com/documentation/corebluetooth?language=objc">Core Bluetooth API documentation</a></li><li><a href="https://developer.android.com/guide/topics/connectivity/bluetooth-le">Android Bluetooth Low Energy Guide</a></li><li><a href="https://developer.android.com/reference/android/bluetooth/package-summary">Android Bluetooth API documentation</a></li></ul><p>Additionally, the NHSX team have open sourced their <a href="https://github.com/nhsx/COVID-19-app-iOS-BETA">iOS</a> and <a href="https://github.com/nhsx/COVID-19-app-Android-BETA">Android</a> Contact Tracing apps and they’re a very good example of how to use Bluetooth on both platforms.</p><p>Stay safe! ❤️</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=df0dabd95d42" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/why-bespoke-contact-tracing-apps-dont-work-so-well-on-ios-df0dabd95d42">Why bespoke Contact Tracing apps don’t work so well on iOS</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[Manually testing HealthKit]]></title>
            <link>https://medium.com/kinandcartacreated/manually-testing-healthkit-f4ad0adccbd7?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/f4ad0adccbd7</guid>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[healthkit]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Wed, 27 Nov 2019 11:37:24 GMT</pubDate>
            <atom:updated>2019-11-27T13:11:17.021Z</atom:updated>
            <content:encoded><![CDATA[<p>Because any app can read and write to the Health store on iOS and watchOS, (with permission from the user), it means that your app has to be ready to respond to changes made out of your app’s control.</p><p>This is a relatively new concept in iOS, since generally the sandbox environment apps run in gives you total control over everything that happens.</p><p>In this post I’ll focus specifically on a way to <em>manually</em> test HealthKit, which is especially useful if your app responds to events that other apps write to the shared store in the Health app on iOS (and watchOS).</p><h4>Let’s make a HealthKit app!</h4><p>Every good post comes with an example.</p><p>Let’s start by creating a simple <a href="https://developer.apple.com/documentation/healthkit">HealthKit</a> app. Fire up Xcode and choose <strong>[File]</strong> &gt; <strong>[New Project]</strong> &gt;<strong> [iOS]</strong> &gt; <strong>[Single View App]</strong> and then name it <strong>FallDetector</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8BiLRyUZsfAcuM1PsJemMw.png" /><figcaption>Our fresh new app’s Xcode project</figcaption></figure><p>Our app is going to detect when a user falls over (while wearing an Apple Watch), so we can take some action to help them and make sure they’re okay!</p><p>Before we can use any HealthKit APIs, we first need to tell Xcode that our app will use it, so click on <strong>[Signing &amp; Capabilites]</strong> and add the HealthKit capability:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VktVkf-hOjinq7HzwcXxUQ.png" /><figcaption>Adding the HealthKit capability</figcaption></figure><p>Additionally, we’ll also need to provide a reason for reading from the Health store, so click on the <strong>[Info]</strong> tab and add a new entry called NSHealthShareUsageDescription with a string value of We want to help you if you fall!:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iFXeGbFEB2X4arEeNhAfRA.png" /><figcaption>Adding the usage description</figcaption></figure><blockquote><strong>NOTE: If you’re using Xcode 11 for this example you’ll need to delete the `Application Scene Manifest` entry in the Info.plist for this tutorial.</strong></blockquote><p>Next, open AppDelegate.swift and replace the existing code with the following:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/78fe095541da5dd0bb7351cb6bee53cf/href">https://medium.com/media/78fe095541da5dd0bb7351cb6bee53cf/href</a></iframe><p>In the code above, we request permission to read falls when the app launches, and then set up a query that will be called whenever the Health store detects a new fall is added.</p><blockquote><strong>Note: In our example, you have to open the app to receive the event after a fall is detected. HealthKit provides a way to automatically notify and launch our app in the background if a fall is detected, but that’s out of the scope of this post!</strong></blockquote><p>Go ahead and run the app and accept the permissions to read falls.</p><h4>Now let’s test it!</h4><p>So, how do we actually test this?! For an Apple Watch to detect if a user falls, you’d need to either actually fall over (which might be fun the first one or two times), drop your watch and hope the fall algorithms detect it, or maybe smack your hand on the table so hard it hurts.</p><p>None of these are a very robust (or safe!) way of testing if a user falls, so what else can we do?</p><p>Remember I said that any app can write to the Health store on iOS? We can use that to our advantage!</p><p>It might not be immediately obvious, but you can add more than one app target to an Xcode project or workspace, so we’re going to add a new app target (which will be a very simple app) that can run independently of our main app, and use that to write to to the Health store.</p><p>In Xcode, click on the FallDetector project in the navigator, then under Targets, click the + to add a new iOS Single View App. Call it <strong>FallDetectorTestHelper</strong> and click finish:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MKIgCuAXddc7dQR77x_sSA.png" /><figcaption>Adding the test helper app</figcaption></figure><p>Now we have two separate apps in the same Xcode project, we can run them independently.</p><p>We’re going to keep our <strong>FallDetectorTestHelper</strong> very simple for this example and just make it write a new fall to the Health store every time it is launched.</p><p>Because it’s a real app, we’ll need to give it the same HealthKit capabilities that the <strong>FallDetector</strong> app does, and also give it a privacy usage description for NSHealthUpdateUsageDescription:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G6UiHol0p9y7VXzYexowEw.png" /><figcaption>Adding the usage description for the helper app</figcaption></figure><p>Once you’ve done that, open the AppDelegate.swift for <strong>FallDetectorTestHelper</strong> and then add the following code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5d6333110bf99392c80cfdebc6093886/href">https://medium.com/media/5d6333110bf99392c80cfdebc6093886/href</a></iframe><p>Now go ahead and run the <strong>FallDetectorTestHelper</strong> app and accept the permissions. You’ve now written a new fall to the store, so swap back to the FallDetector app and get the alert that a fall was detected!</p><blockquote><strong>NOTE: You can actually add entries manually in the Health app, but this changes between iOS versions and is super fiddly to do. By creating our own super simple helper app we’re in full control, which means our testers can just get on with testing the app’s behaviour, without having to worry about different iOS versions etc.</strong></blockquote><h4>Wrapping up</h4><p>This very simple example could be expanded so that the <strong>FallDetectorTestHelper</strong> app can have some simple UI that allows testers to add different values and types to the Health store, depending on what your app responds to.</p><p>Additionally, this could be used for UI testing. Since you can interact with multiple apps with XCTest UI testing, so you can automate HealthKit interactions too.</p><p>Since both apps share the same codebase, you can also share code between them so that you’re not duplicating code. This is even easier if you’re <a href="https://edit.theappbusiness.com/modular-ios-strangling-the-monolith-4a6843a28992">splitting your code up into modules</a>, which is something we use extensively at TAB.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f4ad0adccbd7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/manually-testing-healthkit-f4ad0adccbd7">Manually testing HealthKit</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[Sanitizing user input with Swift 5.1]]></title>
            <link>https://medium.com/@KaneCheshire/sanitizing-user-input-with-swift-5-1-e9bce97f9b2b?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/e9bce97f9b2b</guid>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Fri, 26 Jul 2019 17:45:42 GMT</pubDate>
            <atom:updated>2019-07-27T22:43:32.454Z</atom:updated>
            <content:encoded><![CDATA[<h3>Sanitising user input with Swift 5.1</h3><p>Okay, so I’m a bit behind, but how amazing are @propertyWrappers in Swift 5.1?!</p><h4>Recap</h4><p>Formerly called “property delegates”, property wrappers are <em>just that</em>. They’re a wrapper around a property, and they’re simpler to set up than you might expect.</p><p>A property wrapper is just a type annotated with @propertyWrapper :</p><pre>@propertyWrapper<br>struct Wrapper {</pre><pre>  var wrappedValue: Value</pre><pre>}</pre><p>And you use it on any property that has a type matching the wrappedValue type:</p><pre>struct Thing {</pre><pre>  @Wrapper<br>  private var value: Value</pre><pre>}</pre><p>It’s as simple as that, now when value is changed, it’s actually the wrappedValue that changes. This becomes powerful when you know that you can set a specific get and set, to be called when the wrapped property is retrieved or set.</p><p>Even better, if you create an initialiser for Wrapper, you can pass an argument in when wrapping a property:</p><pre>@propertyWrapper<br>struct SomeWrapper {</pre><pre>  var wrappedValue: SomeValue</pre><pre>  init(_ argument: Argument) {}</pre><pre>}</pre><pre>struct Thing {</pre><pre>  @Wrapper(Argument())<br>  private var value: Value</pre><pre>}</pre><h4>Sanitising user input</h4><p>There are a few good examples of how this can be used already, like writing to UserDefaults, or my personal favourite; clamping a value between a range, but another nice idea is to use it to sanitise user input.</p><p>First we need to create a Sanitized property wrapper:</p><pre>@propertyWrapper<br>struct Sanitized {</pre><pre>  var wrappedValue: String {<br>    get { value } // No need for the `return` in Swift 5.1 🎉<br>    set { value = newValue.removingOccurrences(of: allowed.inverted) }<br>  }</pre><pre>  private var value: String = &quot;&quot; // This holds our sanitized value<br>  private let allowed: CharacterSet</pre><pre>  init(_ allowed: CharacterSet) {<br>    self.allowed = allowed<br>  }</pre><pre>}</pre><p>In this property wrapper named Sanitized, we’re requiring it to be initialised with an allowed CharacterSet. This is nice because there are already a few default CharacterSets, and you can also create your own.</p><p>When something tries to set the wrappedValue, we’ll use the newValue to sanitise it by removing the occurrences of any characters <em>not</em> in the allowed CharacterSet and storing in the private value property.</p><blockquote>NOTE: <em>removingOccurrences(of:)</em> doesn’t really exist in Foundation, but you get the idea).</blockquote><p>When something tries to get the wrappedValue, we’ll just return whatever the most recently sanitised value is!</p><p>Here’s a really simple example of how you could use the property wrapper:</p><pre>final class SignUpController: UIViewController {</pre><pre>  @Sanitized(.alphanumerics)<br>  private var name: String</pre><pre>  @Sanitized(.decimalDigits)<br>  private var number: String</pre><pre>}</pre><p>Here we have two private properties: name and number, representing the user’s input in a controller for signing up.</p><p>When the user enters a name or number you can set it in those properties and it’ll automatically be sanitised for you, with no need to call any extra functions yourself 🎉.</p><p>Property wrappers are also completely unit testable, since they’re just structs/classes:</p><pre>func test_sanitized() {<br>  <br>  var sanitized = Sanitized(.alphanumerics)<br>  sanitized.wrappedValue = &quot;a~&quot;<br>  XCTAssertEqual(sanitized.wrappedValue, &quot;a&quot;)</pre><pre>}</pre><p>Pretty sure this is just scratching the surface of what we’ll be able to improve with property wrappers, but this gets me very excited for future development in Swift. I also really hope we also see more of these annotations like @propertyWrapper and @functionBuilder that allow us to create our own custom annotations in future versions of Swift.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e9bce97f9b2b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Modern modular apps with Xcode 11 and Swift Package Manager]]></title>
            <link>https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-11-and-swift-package-manager-6b4afa0125be?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/6b4afa0125be</guid>
            <category><![CDATA[swift-package-manager]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[xcode11]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[engineering]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Tue, 04 Jun 2019 16:06:07 GMT</pubDate>
            <atom:updated>2020-08-04T11:37:09.018Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*id2IkTPAw4sJxQtVf-VaHQ.png" /></figure><blockquote>NOTE: Xcode 12 improves Swift Package Manager support for creating modular apps, so I’ve written a <a href="https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-12-and-swift-package-manager-a84aedace575">follow up post</a> with how to use it.</blockquote><p>Xcode 11 beta 1 is out, and it is extremely exciting! Until now, the best way to manage dependencies was with Cocoapods or Carthage, but today that changes.</p><p>Xcode 11 and Swift Package Manager make it ridiculously easy to make modular apps; Xcode 11 automatically resolves dependencies when you build, and even gives useful error messages!</p><p>I’ll show you how easy it is.</p><h4>Step 1</h4><p>In Xcode 11, create a new Workspace from File &gt; New &gt; Workspace, name it AmazingApp and save it somewhere sensible:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VrdOeCeU-6RE6jsErjCIug.png" /></figure><h4>Step 2</h4><p>Create a new Project from File &gt; New &gt; Project. Choose Single View App, name it AmazingApp and click Next:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0XnPiZST1qdFvkaytH5HeA.png" /></figure><h4>Step 3</h4><p>Choose AmazingApp from the “Add to:” drop down, make sure the right location to store it is selected and click create:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gvhQgofn2WiY4e6ZAT_ntg.png" /></figure><h4>Step 4</h4><p>That’s your app and workspace created. Lets add a module!</p><p>From the bottom left of the workspace, click the + button and choose “New Swift Package”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/568/1*5LaWEg2FFlBNuSVLRCRJHA.png" /></figure><p>Name it FantasticFeature, make sure it’s being stored in the right place and click Create:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*e4ktYBgmqLUJERUdzc3ojw.png" /></figure><h4>Step 5</h4><p>Now you’ve created your module, you need to add it as a framework to your app so you can use it. Click on the AmazingApp project in the navigator on the left, choose your target (also called AmazingApp) and scroll down to Frameworks, Libraries, and Embedded Content:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nzDP0vgZR-Hq3xP43R9XYA.png" /></figure><p>Click the +, find your module’s name (FantasticFeature) and click “Add”:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*L2GE28hr1rllfnIBHg13RQ.png" /></figure><h4>Step 6</h4><p>That’s it! You’ve added a new module and you can import FantasticFeature into any file in your main target. But it gets better! Let’s add Alamofire as a dependency to the FantasticFeature:</p><p>Find the Package.swift file for your module and open it:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GOS4IC7HJkgm45GScwBYDQ.png" /></figure><p>In the root Dependencies array, add Alamofire as a dependency:</p><p>.package(url: &quot;https://github.com/Alamofire/Alamofire.git&quot;, from: &quot;5.0.0-beta.5&quot;)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5Lc0-gRBSEDPW_ybhorXBw.png" /></figure><p>Build your app and you’ll see Alamofire automatically get resolved as a dependency in the workspace 😍:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Sq-_nWtmUVjHiO_1iAxezg.png" /></figure><h4>Step 7</h4><p>You need to declare which target in the FantasticFeature uses Alamofire, so do that by adding .product(name: &quot;Alamofire&quot;) to the array of dependencies specifically for the FantasticFeature <strong>target</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2quBX6KiG8-aujlivyLR_w.png" /></figure><h4>Step 8</h4><p>If you build the app you’ll get no errors, hooray! But if you try to import Alamofire into a file in the FantasticFeature target (like FantasticFeature.swift) you’ll get an actually useful error saying <em>“Compiling for iOS 8.0, but module ‘Alamofire’ has a minimum deployment target of iOS 10.0”</em>.</p><p>Easy fix! Open up Package.swift again in your FantasticFeature module, and declare which platforms your module supports with platforms: [.iOS(.v13)]:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zkgsI1Lspy_zzUPv4gU5YQ.png" /></figure><p>Save the file, build your app, and the error is gone! You can now use Alamofire in your FantasticFeature module, and you can import your FantasticFeature module into your main app.</p><h4>Step 9</h4><p>One last piece of the puzzle to figure out is how to create another module that can be imported into your FantasticFeature module. Thankfully that’s easy too!</p><p>Create a new Swift Package called Common, and declare it as a dependency for FantasticFeature:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*x5FG7iw2r-YaBWijz7ptPw.png" /></figure><p><strong>And that’s it</strong>! Modern modular app architecture using nothing but Swift Package Manager built directly into Xcode 11. Not bad for a first beta.</p><p><a href="https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-12-and-swift-package-manager-a84aedace575">Read my follow up post</a> for how to go even further with Xcode 12 to use SPM to manage your modules completely.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6b4afa0125be" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/modern-modular-apps-with-xcode-11-and-swift-package-manager-6b4afa0125be">Modern modular apps with Xcode 11 and Swift Package Manager</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[From WWDC information overload to information zen]]></title>
            <link>https://medium.com/kinandcartacreated/from-wwdc-information-overload-to-information-zen-8c04cf1eb0ea?source=rss-203911794be4------2</link>
            <guid isPermaLink="false">https://medium.com/p/8c04cf1eb0ea</guid>
            <category><![CDATA[wwdc]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[engineering]]></category>
            <dc:creator><![CDATA[Kane]]></dc:creator>
            <pubDate>Tue, 04 Jun 2019 10:13:51 GMT</pubDate>
            <atom:updated>2019-06-04T11:28:33.742Z</atom:updated>
            <content:encoded><![CDATA[<h4>A strategy for coping with WWDC</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6uvZEKyDwfsMBiQe30Gdww.jpeg" /></figure><p>Each year at <a href="https://developer.apple.com/wwdc19/">WWDC</a>, Apple unveil new features and APIs for their growing roster of platforms.</p><p>Some years are more exciting than others, but since this year is <a href="https://developer.apple.com/xcode/swiftui/">especially exciting</a> and subjectively packed full of <a href="https://developer.apple.com/ipad-apps-for-mac/">new stuff</a>, I’d like to offer a plan for dealing with the overwhelming wealth of new information, not to mention chronic <a href="https://www.urbandictionary.com/define.php?term=Fomo">FOMO</a>, and the feeling like you’re immediately lagging behind everyone so vocal on Twitter.</p><p>Unsurprisingly, the key is to be methodical and organised.</p><h4>The Keynote</h4><p>The public WWDC Keynote is fun to watch, but you don’t need to have FOMO if you don’t watch it live, or even watch it at all.</p><p>This presentation is primarily Apple’s PR platform to get everyone who isn’t a developer, or self-professed nerd, excited about the upcoming changes to their products. It’s always full of slightly tedious spiel about how well Apple are doing and that they’re the best at doing everything.</p><p>The real important stuff to watch is in the next scheduled event, the Platforms State of the Union.</p><h4>Platforms State of the Union</h4><p>This is where the juicy stuff is. While it can be fun to watch the main Keynote with friends and colleagues, I recommend settling down to watch PSotU on your own, somewhere that you can’t be distracted and with a good connection.</p><p>It’s also completely fine to not watch this live and focus on it when you get time.</p><p>If time is an issue, you can get away with not watching the main Keynote at all as a developer because PSotU will reliably cover all the big important announcements, with the benefit of being in a more developer-focused way.</p><p>Before going any further it’s a good idea to plug in any devices you want to dedicate to running the new betas of iOS, watchOS, macOS etc, as well as making sure they’re already running the latest releases of their respective platform. You should also kick off the downloads for any available beta software you want to install, because it can be slooooow, and you can forget about it while you’re watching PSotU.</p><p>When you settle down to watch the event, crack open your favourite note taking app and begin making notes about anything that piques your interest. At this point just keep it brief, but if you want to make it easier to find what you made a note about you can make a rough note of the time in the video as you make a note. This is when not watching it live will help because you can easily pause and rewind.</p><p>Once it’s over, I then like to take the time to tidy up my notes and start to prioritise them in the order I find most interesting.</p><h4>API diffs</h4><p>Chances are now you’ve got a good idea of what you want to learn about first, but before you do anything it’s a good idea to start installing any beta software that has finished downloading. It can take a while, and you can let that run while looking at the next bit.</p><p>After making my initial list of things to learn about, there’s a few other things I like to do; starting with checking out the API diffs.</p><p>If you mosey on over to the <a href="https://developer.apple.com/documentation/">developer docs</a>, you can get them to <a href="https://developer.apple.com/documentation?changes=latest_minor">display the changes</a> between the last version of Xcode and the new beta. On each page at the top it will give you a quick overview of anything modified (purple), new/added (green), and deprecated (red), as well as an indicator around each new item on the page.</p><p>On the “root” page of the list of frameworks you can see which frameworks are new or modified, and you can use that to drill down and learn about what has changed in any of the frameworks you’re interested in.</p><p>This step is important (and fun), especially if you’re already making and maintaining apps, because sometimes small changes here aren’t mentioned in any WWDC video.</p><p>As you drill down into frameworks and find new stuff, since it’s a web page you can grab a link and add to your notes.</p><h4>Release notes</h4><p>When you’re ready, the next step is to start to take a look at the <a href="https://developer.apple.com/documentation/ios_ipados_release_notes">release notes</a> for the platforms you’re interested in, but also <a href="https://developer.apple.com/documentation/xcode_release_notes">Xcode</a> which can be a gem of a place to find unmentioned new features.</p><p>Release notes can sometimes take a while to show up, but by doing it at this stage they should be available.</p><p>They can be quite lengthy, so again I recommend adding anything you are interested in to your notes. It’s a good idea to make a note of any bugs that can affect what you’re working on or interested in learning about. Thankfully Apple provide bug numbers for everything so you can just make a brief note and include the bug number to quickly find it in the release notes later (as well as quickly find out if it’s been fixed in subsequent release notes).</p><h4>One more thing</h4><p>At this point you should have a nice prioritised and tidy list of notes and information to guide you to where to start. But there is one final thing I like to do, which is best done at this point now you have an idea of what you want to learn about.</p><p>Using either the official WWDC app (available from the <a href="https://itunes.apple.com/gb/app/wwdc/id640199958?mt=8">App Store on iOS, iPadOS and tvOS</a>), or the incredible <a href="https://wwdc.io">unofficial app for macOS</a>, you can go through all of the video sessions that are now available to browse and favourite the ones that are related to the stuff you’ve identified as areas you want to learn about.</p><p>You now know where and <em>when</em> that information will be available, and you can start to plan your learning time accordingly.</p><p>If you’re not actually at WWDC, although you don’t have access to the labs or the people, you do have the luxury of being able to watch all of the videos at a time that suits you, sometimes even before people in San Jose.</p><h4>A footnote on Twitter</h4><p>Twitter is a great place to watch stuff live with your followers and followees. It can be extremely distracting though and you can really quickly find yourself feeling like you’re falling behind because people have more time to spare than you to play around and explore.</p><p>It’s important to remember that you’re not a worse developer because you’ve got less time to spend on playing around with new stuff. (In fact I would argue you’re a <em>better</em> developer because you’ve actually got stuff to be doing 😉)</p><p>You cannot do everything at once, so pick what is most important to <em>you</em> and move onwards from there.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8c04cf1eb0ea" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kinandcartacreated/from-wwdc-information-overload-to-information-zen-8c04cf1eb0ea">From WWDC information overload to information zen</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>