<?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 Quang NGO on Medium]]></title>
        <description><![CDATA[Stories by Quang NGO on Medium]]></description>
        <link>https://medium.com/@nqtuan86?source=rss-3a776011c59a------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*vsPUMwBFS6H7n8X6JzYImg.jpeg</url>
            <title>Stories by Quang NGO on Medium</title>
            <link>https://medium.com/@nqtuan86?source=rss-3a776011c59a------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 21:24:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@nqtuan86/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[Getting Started With iOS Animation (Part 3)]]></title>
            <link>https://medium.com/better-programming/getting-started-with-ios-animation-part-3-e6cfaceba486?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/e6cfaceba486</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Fri, 10 Jul 2020 11:43:16 GMT</pubDate>
            <atom:updated>2020-07-10T11:43:16.036Z</atom:updated>
            <content:encoded><![CDATA[<h4>How to animate transitions between view controllers</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZjiiEIeZ6z76fS2FANpbdQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@nathananderson?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Nathan Anderson</a> on <a href="https://unsplash.com/s/photos/transition?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Welcome the third and final part of our Animation series. In this story, we will discuss how to implement the animation when transiting between view controllers.</p><p>You can also find parts one and two here:</p><ul><li><a href="https://medium.com/dev-genius/getting-start-with-ios-animation-part-1-7bd3a673bee4">Getting Start with iOS Animation (part 1)</a></li><li><a href="https://medium.com/better-programming/getting-start-with-ios-animation-part-2-65f5bcd0c087">Getting Start With iOS Animation (Part 2)</a></li></ul><p><strong>Note</strong>: I recommend starting where we left at the last part, so you can download the project <a href="https://www.dropbox.com/sh/hirw5786plbyspb/AAAdXMiQkuXE43Yup3llAPDOa?dl=0">here</a>. Otherwise, you can still follow this tutorial by creating two view controllers.</p><p>At this point, we have LoginViewController and GiftViewController:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*qA7O5CmybYtl_mMCqHl43A.gif" /></figure><p>The animation on the screen is great, but the transition between theses two views seems ordinary, so we will improve it by implementing some juicy animation. Here’s the final expected result:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*Nbh4E2lhoN9OrlkjqCD1ZQ.gif" /></figure><p>Actually, we will go the extra mile by adding a controllable dismiss transition, which means by swiping from the left edge of the screen, the animation can move forward and backward a finger drag:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*JiyMZ8Jzmt2f6a7b2x48LQ.gif" /></figure><p>You may see the code seems intimidating at first, but actually the principle is simple. The transition animation can be done by creating a class conform with UIViewControllerAnimatedTransitioning. Then, we inject it in the UIViewControllerTransitioningDelegate of a view controller.</p><p><strong>Tip</strong>: Animation parameters were found through trial and error. We often need to monitor closely each move we make, so we need to make that move slower. The simulator provides a great function for slow motion: go to Debug and select Slow Animations.</p><h4>Present transition animation</h4><p>We begin with the Present transition. Here are the animation steps:</p><ul><li>Rotating the “Open” button 90 degrees along the y-axis clockwise.</li><li>Display the gift snapshot view at the place and with the size of “Open” button, but the initial place is 90 degrees anti-clockwise on the y-axis. It’s because it helps the button rotating looks continuous.</li><li>Then we rotate it along y-axis clockwise 90 degrees.</li><li>Zoom the gift view out to fill the screen.</li></ul><p>Here’s the code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/30e8c0dbe57bf6001d1234baaf6a38b6/href">https://medium.com/media/30e8c0dbe57bf6001d1234baaf6a38b6/href</a></iframe><p>The most important part is taking a snapshot of the destination view:</p><p>let snapshot = toVC.view.snapshotView(afterScreenUpdates: true)</p><p>And here the code of each step:</p><p><strong>Rotating the “open” button 90 degrees along the y-axis clockwise</strong>:</p><pre>UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1/4) {<br>     fromVC.loginButton.layer.transform = CATransform3DMakeRotation(CGFloat(-Double.pi / 2), 0.0, 1.0, 0.0)<br>}</pre><p>By using UIView.addKeyframe, we can specify the animation’s duration of each step relative to the whole animation’s duration. Here we want the rotation time of the “Open” button take a quarter of the whole duration.</p><p><strong>Rotating the Snapshot destination view 90 degrees</strong>:</p><p>But first, we must initialize it at 90 degrees anti-clockwise on the y-axis. We do this before the whole animation.</p><pre>snapshot.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi / 2), 0.0, 1.0, 0.0)</pre><p>And then rotate it after rotating the “Open” button:</p><pre>UIView.addKeyframe(withRelativeStartTime: 1/4, relativeDuration: 1/4) {<br>     snapshot.layer.transform = CATransform3DMakeRotation(0.0, 0.0, 1.0, 0.0)<br>}</pre><p><strong>On the final step, we zoom out the snapshot to match the final destination view</strong>:</p><pre>UIView.addKeyframe(withRelativeStartTime: 2/4, relativeDuration: 1/2) {<br>     snapshot.frame = finalFrame<br>}</pre><p>At the completion of this whole animation, we do the cleanup:</p><ul><li>Display the destination view,</li><li>Remove the snapshot, and</li><li>Reset the “Open” button position.</li></ul><p>And the present animation was born. Now, all we have to do is to wire it to our view controllers. So when the app prepares the segue, we must specify that we want to use our custom transition (by specifying transitioningDelegate) instead of the default one:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/43b2c1070e1a768813a978cbcc412bb8/href">https://medium.com/media/43b2c1070e1a768813a978cbcc412bb8/href</a></iframe><p>And then feed our animation instance in the right delegate function:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d55b0a2df83d694b1f02a0e965388595/href">https://medium.com/media/d55b0a2df83d694b1f02a0e965388595/href</a></iframe><p>And it’s done. Run the app and enjoy the first animation.</p><h4>Dismiss transition animation</h4><p>Since we successfully created the present transition, we will just do the same thing to dismiss one.</p><p>Here’s the code for dismissing animation:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6b5d5f42385ffb1ecd929ec5d224da08/href">https://medium.com/media/6b5d5f42385ffb1ecd929ec5d224da08/href</a></iframe><p>Just ignore SwipeInteractiveTransition for now. We talk about it later.</p><p>Here we’ll find the same pattern of code that we wrote in Present animation, just notice that .to and .from view controller was inverse.</p><p>We will create the dismiss view in three steps:</p><p><strong>Zoom out the current view to the size of the destination button</strong>:</p><pre>UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1/2) {<br>     snapshot.frame = <strong>self</strong>.destinationFrame<br>}</pre><p><strong>Rotate it 90 degrees on the y-axis</strong>: We also rotate the “Open” button by 90 degrees so at this moment we won’t see the “Open” text:</p><pre>UIView.addKeyframe(withRelativeStartTime: 1/2, relativeDuration: 1/4) {<br>     snapshot.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi/2), 0.0, 1.0, 0.0)<br>     toVC.loginButton.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi/2), 0.0, 1.0, 0.0)<br>}</pre><p><strong>Finally, rotate the “Open” button back to the right position:</strong></p><pre>UIView.addKeyframe(withRelativeStartTime: 3/4, relativeDuration: 1/4) {<br>     toVC.loginButton.layer.transform = CATransform3DIdentity<br>}</pre><p>Now that we have the animation created, we just need to wire it in the UIViewControllerTransitioningDelegate:</p><pre>func animationController(forDismissed dismissed: UIViewController) -&gt; UIViewControllerAnimatedTransitioning? {<br>     return DismissViewControllerAnimation(destinationFrame: loginButton.frame)<br>}</pre><p>Cool, now we finished all the animations. Run the app and enjoy the magic!</p><h4>Control the animation</h4><p>iOS makes it really easy to give user interaction with the animation. And it works the same way as we did with these two animations. First, we create a subclass of UIPercentDrivenInteractiveTransition and then inject it in the function interactionControllerForDismissal of our UIViewControllerTransitioningDelegate . The class UIPercentDrivenInteractiveTransition provides three functions:</p><ul><li>update(): Tells us how much of the transition was complete. 0.0 is the beginning of transition and 1.0 is the end of the transition.</li><li>cancel(): Cancel the transition. In our case, it will cancel the dismiss process.</li><li>finish(): Finish the transition. In our case, it will dismiss the Gift view and show the Login view.</li></ul><p>We usually use this interactive transition combined with gesture recognizer, since it gives user the ability to control the transition. Here’s the code of this subclass:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e9743a31433be9f93cd391e177b9557b/href">https://medium.com/media/e9743a31433be9f93cd391e177b9557b/href</a></iframe><p>We will addUIScreenEdgePanGestureRecognizer to the gift view. This recognizer can detect a dragging from the edge of the screen. Then, based on how much the user is dragging, we use update to control the transition. When the gesture ends, we check if the progress is more than half, then we go forward and finish the dismissal; otherwise, we cancel it.</p><p>We can instantiate this controller in GiftViewController:</p><pre>private(set) var swipeTransition: SwipeInteractiveTransition?</pre><pre>override func viewDidLoad() {<br>     super.viewDidLoad()<br>     setupUI()<br>     swipeTransition = SwipeInteractiveTransition(viewController: self)<br>}</pre><p>And then inject it in a function of UIViewControllerTransitioningDelegate. Here’s the final version of this delegate:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6dda1e4a3f06a95600a667f870ec0f6f/href">https://medium.com/media/6dda1e4a3f06a95600a667f870ec0f6f/href</a></iframe><p>Awesome! We finished it. Now it’s time to admire our stunning transition animation!</p><h3>Where to Go From Here</h3><p>You can download the final project <a href="https://www.dropbox.com/sh/pnoix06x4zzx8rp/AAAZ6j0ILbuHFFAvepk99wYia?dl=0">here</a>.</p><p>In this tutorial, we learned:</p><ul><li>How to implement an animated transition between the view controller</li><li>How to give user control on this animation</li></ul><p>I hope you like this story. If you want to know more about animation, you can check my two first stories.</p><p>The first part is about animating views:</p><p><a href="https://medium.com/dev-genius/getting-start-with-ios-animation-part-1-7bd3a673bee4">Getting Start with iOS Animation (part 1)</a></p><p>The second part is about animating a sequence of image (a movie-like animation):</p><p><a href="https://medium.com/better-programming/getting-start-with-ios-animation-part-2-65f5bcd0c087">Getting Start With iOS Animation (Part 2)</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e6cfaceba486" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/getting-started-with-ios-animation-part-3-e6cfaceba486">Getting Started With iOS Animation (Part 3)</a> was originally published in <a href="https://betterprogramming.pub/">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting Started With iOS Animation (Part 2)]]></title>
            <link>https://medium.com/better-programming/getting-start-with-ios-animation-part-2-65f5bcd0c087?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/65f5bcd0c087</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Wed, 24 Jun 2020 21:48:20 GMT</pubDate>
            <atom:updated>2020-06-28T18:10:48.174Z</atom:updated>
            <content:encoded><![CDATA[<h3>Getting Started With iOS Animation (Part 2)</h3><h4>How to create movie-like animations</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PP8FGMLjvOpRajEtmAVX-Q.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@bryanhanson?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Bryan Hanson</a> on <a href="https://unsplash.com/s/photos/hummingbird?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>In the <a href="https://medium.com/@nqtuan86/getting-start-with-ios-animation-part-1-7bd3a673bee4">first part of this series</a>, we learned how to implement UIView animation. In this part, we’ll see how to create an animation from an image’s sequence in iOS.</p><p>We’ll begin with animating a loading-circle sequence’s images using only UIKit build-in functions. Next, we’ll see how to implement the <a href="https://airbnb.design/lottie/">Lottie</a> library to make this same kind of animation (the singing bird) but much more elegantly and easily — while also providing for better performance. Finally, we’ll do a comparison of the various methods and tools that can produce this same kind of animation.</p><p>So here’s the desired result we should have at the end of this tutorial:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*rA5aAEi4i48lDFsMxXhG2A.gif" /></figure><p>This tutorial is developing from the previous tutorial. You can download that project <a href="https://www.dropbox.com/sh/nnfgxk6umaypb8o/AABVjUozrFZ1aZLJEYCIlRrra?dl=0">here</a>. But you can follow along with this tutorial even if you’re starting from scratch with a project. Just keep in mind this story is on a separate view controller and has has a function, Go Back, enabling one to dismiss and go back to previous (first) view controller.</p><h3>Set Up the View</h3><p>Now we have to set up the initial view components:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b89c7935427b71cd5f5e0f553a976522/href">https://medium.com/media/b89c7935427b71cd5f5e0f553a976522/href</a></iframe><p>As you may have noticed, we inserted a UIImageView into the center of the view and added a back button at the top left. Now we don’t have much to see here since we only have a back button to go back to the previous page. In viewDidAppear, we call the animateSequenceImages function, but right now it’s empty.</p><h3>Animating an Image Sequence Using UIKit</h3><p>Firstly, we’ll create the loading animation. So we should have an image’s sequence as assets provided to this animation. We need to create a reference folder of images, like this, in Xcode:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8zarsgykraG6sWBTbZEaoA.png" /></figure><p>You can download the project via the link at the end of this story. Or you can download a GIF file you found on Google and split it into an image sequence. If you do so, I suggest using <a href="https://ezgif.com/split">ezgif</a> to split that GIF file.</p><p>Cool! We had the assets — now animate it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/475eeaa0d695ac9bd5a66c86ac616294/href">https://medium.com/media/475eeaa0d695ac9bd5a66c86ac616294/href</a></iframe><p>It’s pretty straightforward:</p><ol><li>Feed the UIImageView with all of the UIImage assets through the animationImages variable.</li><li>Assign the animation duration (animationDuration = 5).</li><li>We don’t repeat the animation (animationRepeatCount = 0).</li><li>Finally, start the animation (sequenceImageView.startAnimating()).</li></ol><p>Actually, we’d like to fade out this loading view while it’s animating — that’s why we make the animating duration five seconds — but we fade it out after just two seconds.</p><p>Here’s the result so far:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*QOAEcWbfX9-yfmi7kRbaZA.gif" /></figure><h3>Animating With Lottie</h3><p>Lottie is an open-source framework originally created by Airbnb:</p><blockquote>“Lottie is an iOS, Android, and React Native library that renders After Effects animations in real time, allowing apps to use animations as easily as they use static images.” — <a href="https://airbnb.design/lottie/">Lottie’s official site</a></blockquote><p>Firstly, we need to install lottie-ios in our project. Lottie supports CocoaPods, Carthage, and Swift Package Manager. You can consult the details in their <a href="https://github.com/airbnb/lottie-ios">GitHub repo</a>.</p><p>Secondly, we need to find the asset for Lottie. <a href="https://lottiefiles.com/">LottieFiles</a> is a great resources to search for animating assets. Download any free JSON you found here, and name it bird.json. Drag and drop this file into your current project. An animating JSON file for Lottie is like a PNG for a UIImageView.</p><p>Then, we set up the Lottie view (AnimationView) in our view controller. Actually, using AnimationView is very similar to an ordinary UIImageView. We declare the variable:</p><pre><strong>private</strong> <strong>var</strong> giftView: AnimationView!</pre><p>Now we can initialize this view in the setupUI() function:</p><pre>giftView = AnimationView(name: &quot;bird&quot;)<br>giftView.frame = <strong>self</strong>.view.frame<br>giftView.contentMode = .scaleAspectFit<br>giftView.alpha = 0<br>giftView.loopMode = .autoReverse<br>view.addSubview(giftView)</pre><p>AnimationView(name: “bird”) is to tell the Lottie framework to look for the file bird.json in the main bundle. We can notice that besides loopMode, everything else is exactly similar to an UIImageView. loopMode tells us that the animation will be played forward and backward until stopped.</p><p>Now we want to trigger the singing-bird animation when the loading fades out. We’ll call animateGift() at the completion of animateSequenceImages()in viewDidAppear:</p><pre>animateSequenceImages {<br>    self.animateGift()<br>}</pre><p>Inside animateGift() , we fade in the AnimationView:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/61a37be90cece0b5a0bc8281576b37c4/href">https://medium.com/media/61a37be90cece0b5a0bc8281576b37c4/href</a></iframe><p>The play() function starts the animation of AnimationView. Here’s our final result:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*rA5aAEi4i48lDFsMxXhG2A.gif" /></figure><h3>Comparing Different Forms of Animation</h3><p>Actually, there’s many ways to embed a movielike animation like this into a view controller.</p><p>Besides Lottie and the image-sequence method we just did, we can also use a GIF, a video, or even code it using a Bézier path and/or a combination of UIView’s animation functions. There are many reasons why designers and developers are starting to prefer Lottie animations over other formats. Let’s compare Lottie to the other options you have.</p><h4>PNG-sequence image</h4><p>One of the biggest drawbacks of PNG-sequence graphics is they’re rather large in size, which can make them something of a hassle to export and manipulate on different interfaces for designers.</p><p>Lottie files, in comparison, are extremely small and conveniently sized, consequently having a quick download speed and keeping your site or app operations as smooth as possible.</p><h4>GIF</h4><p>While smaller than PNG graphics, GIFs are still a pretty space-occupying format, being in average double in size than a simple Lottie animation.</p><p>GIFs are also typically scaled at a fixed size. This means you can’t modify them to better fit to scale on a different interface than where they were originally created. Lottie animations give you the space you need to adjust them to large-scale solutions as well as to smaller-scale screens.</p><h4>Video</h4><p>Regarding a simple and short animation, video content comes up quite often. For video content, particularly live-action stuff, you need to arrange for a host of resources, including props, actors, and locations. Animations are relatively simpler and cheaper alternatives that still get the job done.</p><p>In term of coding, handling a video is much more of a hassle than an AnimationView (which is as simple as a UIImageView). Not to mention: A good animation keeps your visitor engaged and doesn’t compel them to turn it off.</p><h4>Code animation</h4><p>App-development teams want to streamline the development process and make it as cost- or resource-effective as possible.</p><p>Writing animation in code can be a time- and skill-intensive process, not to mention how easy it is to encounter a host of problems while writing the code. Instead of dedicating valued resources to either outsourcing the project or hiring skilled staff, why not use an alternative animation tool in the form of Lottie that is intuitive, scalable, and compatible with multiple platforms?</p><h3>Where to Go From Here</h3><p>You can download the project <a href="https://www.dropbox.com/sh/hirw5786plbyspb/AAAdXMiQkuXE43Yup3llAPDOa?dl=0">here</a>.</p><p>In this article, we learned how to create movielike animation by using PNG-sequence images and Lottie. We also discovered a great resources for Lottie animations: <a href="https://lottiefiles.com/">LottieFiles</a>. And we saw why Lottie outperforms all of the other animation forms when it comes to short animations.</p><p>We finished the second part of the series. In the next part, we’ll see how to animate the transition between view controllers. Here’s the final result of our three-part series:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*Nbh4E2lhoN9OrlkjqCD1ZQ.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=65f5bcd0c087" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/getting-start-with-ios-animation-part-2-65f5bcd0c087">Getting Started With iOS Animation (Part 2)</a> was originally published in <a href="https://betterprogramming.pub/">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Get Started With iOS Animation (Part 1)]]></title>
            <link>https://medium.com/better-programming/getting-start-with-ios-animation-part-1-7bd3a673bee4?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/7bd3a673bee4</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Tue, 09 Jun 2020 12:52:55 GMT</pubDate>
            <atom:updated>2020-07-09T16:38:20.469Z</atom:updated>
            <content:encoded><![CDATA[<h4>How to animate view components</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-67-5Vh7VIHqkjJI9j3dHg.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@cosmictimetraveler?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Cosmic Timetraveler</a> on <a href="https://unsplash.com/s/photos/frame?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Animation is essential to make our apps enjoyable and professional. Users tend to trust and engage more with your app if they feel that the developer has invested effort and been meticulous in making the app more user friendly.</p><p>In this three-part series, we will see a complete stack of animations we can do in iOS:</p><ul><li>View animation. In this first article, we’ll create a view and make the view’s component move in and around.</li><li>Movie-like animation. In this article, we will learn how to implement the Lottie framework and image sequence. At the end, we will compare video, GIF, image sequence, coding animation, and the Lottie framework.</li><li>Transition animation. In this article, we will touch the final and the most complicated part of iOS animation: view controller transition animation.</li></ul><p>Prerequisite: The reader should know how to create view components like UIView, UIButton, and UIImageView.</p><p>During this first part, we will see how to implement all recommended ways of making a view component animated. Furthermore, we analyze the limit and use cases of each method.</p><p>Since one animated image is worth a thousand words, here’s the final result (actually we will add some more user’s interactive animation as a bonus):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*y8bQvtkE_J0Ii9NKECx2NA.gif" /></figure><h3>Setup for This Tutorial</h3><p>Before diving into the animations, we must initialize some view components and add them to the main view. This is the beginning point of all our animations. Please add this code in your initial view controller:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/571ada9d9ff3b8fb553295f6a40f54f4/href">https://medium.com/media/571ada9d9ff3b8fb553295f6a40f54f4/href</a></iframe><p>Basically, what we are doing here is inserting the app logo image and open button (hidden) in the centre of the view. We also added a car ImageView at the footer of our screen. Here’s what’s we have now:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/333/1*a8QuHBab46H0olp5mWO7og.png" /></figure><p>Before diving into the animation code, it’s worth mentioning that creating an animation needs a lot of trial and error. We need to test many times to find out the perfect duration, frame timing, position, and other parameter values. To facilitate the test, we should use the slow-motion tool of the simulator (Simulator -&gt; Debug -&gt; Slow Animations) to monitor the animation.</p><h3>Simplest Form of View Animation: UIView.animated function</h3><p>The easiest way to animate a view is by using UIView.animated function. Here we want to do two things: move the app logo “Animation” to the top and fade in the Open button.</p><p>Add this function to your current code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/46304ecca992e10636b35ab2cefaf103/href">https://medium.com/media/46304ecca992e10636b35ab2cefaf103/href</a></iframe><p>As you may see, this function is quite simple. It contains three inputs:</p><ul><li>withDuration: Specifies the duration of the animation. Here we want to move the logo in one second.</li><li>animations: Describes the final state of this animation. Here we specify the final position (frame) of our logo image view. The function itself will interpolate the origin frame value and destination frame value to animate the action.</li><li>completion (optional): This is a completion handler that informs us of whether the animation sequence was finished or not. Here we make it our own completion.</li></ul><p>Now we execute this function in viewDidAppear. Plus, when the animated logo finishes, we also use the UIView.animate function to fade in the Open button:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d5dc4bf62388f61931123aa1ad954fce/href">https://medium.com/media/d5dc4bf62388f61931123aa1ad954fce/href</a></iframe><p>Now run our app. We should see this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*loggser7ayOCXIH1L4QmIw.gif" /></figure><p>This function is able to work with frame, bound, centre, transform, alpha, and background colour of a view.</p><p>UIView’s animation function has some variants that allow specifying more animation properties, like damping, animation options (easy in, easy out, etc.), delay, and so on. We recommend you read Apple’s documentation to learn more details.</p><h3>Animating Layer Property: CABasicAnimation</h3><p>CABasicAnimation is an object that provides basic, single-keyframe animation capabilities for a layer property. You create an instance of CABasicAnimation using the inherited init(keyPath:) method, specifying the key path of the property to be animated in the render. Like the UIView.animated function, by specifying fromValue and toValue, Core Animation will interpolate the transition values and make the animation. You can consult the full list of key paths in the Core Animation Programming Guide, <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/AnimatableProperties/AnimatableProperties.html">Appendix B</a> and <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/Key-ValueCodingExtensions/Key-ValueCodingExtensions.html#//apple_ref/doc/uid/TP40004514-CH12-SW2">Appendix C</a>.</p><p>We’ll use CABasicAnimation to animate drawing the line around the Open button. To do this, we use four steps:</p><ol><li>Create the Bezier path for that line.</li><li>Inject that path into aCAShapeLayer.</li><li>Create CABasicAnimation object by specifying our animation parameters.</li><li>Execute this CABasicAnimation on our CAShapeLayer by using CATransaction.</li></ol><p>Here’s the code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1e4dd1a882f357fc647b252ab4d9711b/href">https://medium.com/media/1e4dd1a882f357fc647b252ab4d9711b/href</a></iframe><p>The code looks intimidating, but actually most of it is for specifying our animation parameters like duration, start position, end position, timing easyInEasyOut, etc., and those values are found through trial and error.</p><p>We execute this function by replacing the completion of animateLogo with our function self.animateLoginButton(). We receive the result below (please ignore the car moving; we’ll do it later):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*fy0_CZJl4xbE-SZZJqsbIg.gif" /></figure><p>Based on what we just learned here, we can easily create a “shaking” animation based on a user’s touch. Basically, when the user touches the Animation logo, we want the logo to be shaken. As you may already have figured out, that animation will be a position type (go to left and to right), autoreverse, and loop about four or five times. The code should look like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/aeba085d40bec69adcf4cd57476345ca/href">https://medium.com/media/aeba085d40bec69adcf4cd57476345ca/href</a></iframe><p>To wire the tap event to this function, we can register a gesture recognizer to the logo image view in setupUI function:</p><pre>logoImageView.isUserInteractionEnabled = true<br>logoImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(shakeLogo)))</pre><p>Run the code, here’s the result when you tap on the logo image:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*Avj2NSXasDagSnScvHBLHQ.gif" /></figure><h3>Animating With User’s Interaction</h3><p>The most convenient way to interact with a view’s animation is to use UIViewPropertyAnimator. From <a href="https://developer.apple.com/documentation/uikit/uiviewpropertyanimator">Apple’s documentation</a>:</p><blockquote>“A UIViewPropertyAnimator object lets you animate changes to views and dynamically modify your animations before they finish. With a property animator, you can run your animations from start to finish normally or you can turn them into interactive animations and control the timing yourself. The animator operates on animatable properties of views, such as the frame, center, alpha, and transform properties, creating the needed animations from the blocks you provide.”</blockquote><p>Actually, UIViewPropertyAnimator is relatively similar to the UIView.animated function. When we create this object, we must specify a block containing code that modifies the properties of one or multiple views, the timing curve, the duration, and a completion block to execute when animations finish.</p><p>We will apply this object to make the car’s animation. We would like to make it move to the right, then back to the left, infinitely. Plus, we need to catch the user’s tap gesture and then make the car move back. So basically we need three functions. One function runs when the user taps on the car, one makes the car run to the right, and a final one makes it move to the left:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2f8e71baef6c3b908676d39447cba871/href">https://medium.com/media/2f8e71baef6c3b908676d39447cba871/href</a></iframe><p>Now we wire these functions to our view in viewDidAppear and add self.animateCarToRight(). In setupUI(), add the following:</p><pre>carImageView.isUserInteractionEnabled = true<br>carImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(userTapOnCar)))</pre><p>Run the app, and try tapping on the car to see it if it pulls back. Here’s the result:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*qgtMuzQQUwxsqe-RUxtgfA.gif" /><figcaption>Tapping on the car make it goes back</figcaption></figure><h3>Where to Go From Here</h3><p>You can <a href="https://www.dropbox.com/sh/nnfgxk6umaypb8o/AABVjUozrFZ1aZLJEYCIlRrra?dl=0">download the code of this tutorial</a>.</p><p>In this article, we learned how to animate a UIView using the UIView.animated function. We also saw how Core Animation can help us to draw layer animation using a Bezier path and CABasicAnimation. And finally, we figured out how to enable a user’s interaction with the animation.</p><p>We are now experts in animating the view’s components. In the next article, we aim to animate a sequence of images (movie-like animation), and in the final article, we’ll animate transitions between view controllers.</p><p>Here’s what we’ll have after the second part:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*rA5aAEi4i48lDFsMxXhG2A.gif" /></figure><p>And in the final part, we animate the present transition and the dismiss transition. We also learn how to programmatically control the progress of this animation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*Nbh4E2lhoN9OrlkjqCD1ZQ.gif" /></figure><p>I hope you enjoyed this tutorial. See you again soon in the next part.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7bd3a673bee4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/getting-start-with-ios-animation-part-1-7bd3a673bee4">How to Get Started With iOS Animation (Part 1)</a> was originally published in <a href="https://betterprogramming.pub/">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Debug on Recent iOS Simulators and Devices Using Old Xcode?]]></title>
            <link>https://medium.com/swlh/how-to-debug-on-recent-ios-simulators-and-devices-using-old-xcode-93a4fc092e7b?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/93a4fc092e7b</guid>
            <category><![CDATA[deployment]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[debugging]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Fri, 22 May 2020 12:45:57 GMT</pubDate>
            <atom:updated>2020-05-22T12:45:57.792Z</atom:updated>
            <content:encoded><![CDATA[<h4>Run debugging on new iOS Simulators and Device from lower Xcode version</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F5p0nIMoAWw0-jXRY11hsw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@zanilic?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Zan</a> on <a href="https://unsplash.com/s/photos/debug?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Sometimes we need to debugging a new iOS version on an older Xcode. This is usually needed due to various reasons like testing on iOS Beta, be constrained updating to new Xcode and more. So in this story, we will see how to run a simulator and devices that have iOS version higher than the version Xcode supported.</p><p>A common step in setting up for both Simulator and Device is downloading and installing the target Xcode. For example if you want to run iOS 13.4, you need to have Xcode 11.4 or later on your Mac in addition of your current Xcode. Your application folder now must have at least two Xcode versions:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CG91dBdpVv4xYN3pxF3Mpw.png" /></figure><h3>Setup for debugging on newer iOS Simulators</h3><p>Firstly, switch Xcode’s command-line to target version, in this example, we set it to Xcode 11.4. There are two ways doing that:</p><ol><li>Using command line in Terminal:</li></ol><pre>sudo xcode-select --switch /Applications/Xcode11.4.app/Contents/Developer</pre><p>or</p><p>2. On the Xcode you want to run, go to Xcode -&gt; Preferences -&gt; open Locations tab -&gt; change Command Line Tools to target Xcode (11.4)</p><p>Next step, you need to show the list of available simulators. Run this command in your Terminal:</p><pre>xcrun simctl list</pre><p>Now you will see something similar to this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zbTF7EEKXurMPEAi8BMprw.png" /></figure><p>Since all the iOS 13.4 simulators are shutdown, you have to turn on the target simulator by using this command:</p><pre>xcrun simctl boot DEVICE_ID</pre><p>In effect, I will turn on the iPhone 11:</p><pre>xcrun simctl boot 39E956F8-0495-4760-A23E-88DB7887635A</pre><p>Finally, open your current Xcode, you’ll see the simulators you just turn on are ready to use:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/316/1*Hn_RZv6DM7-EzyvpSb19ZA.png" /></figure><p>To resume, here’s the steps:</p><ol><li>Switch Xcode’s command-line</li><li>Find and Boot the target simulator</li><li>Now the target simulator will be available in all your old Xcode</li></ol><h3>Setup for debugging on newer iOS Devices</h3><p>When you tried running old Xcode on your recent iOS iPhone, you are most likely encounter an error similar to this:</p><blockquote><em>The iOS deployment target ‘IPHONEOS_DEPLOYMENT_TARGET’ is set to 13.4, but the range of supported deployment target versions is 10.0 to 13.0.</em></blockquote><p>The reason is your current Xcode 11.1 do not have support files for iOS 13.4. So to fix this, we just need to redirect Xcode 11.1’s device support path to the right one in Xcode 11.4. Using this command line does so:</p><pre>sudo ln -s /Applications/Xcode11.4.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.4 /Applications/Xcode11.1.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport</pre><p>Check the folder at <em>/Applications/Xcode11.1.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport, </em>you’ll see the symbolic link was created:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cPr4iitPKY0AaElFjgTWTw.png" /></figure><p>Now open your old Xcode and run debugging again on your iPhone/iPad, it just works :]</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=93a4fc092e7b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/how-to-debug-on-recent-ios-simulators-and-devices-using-old-xcode-93a4fc092e7b">How to Debug on Recent iOS Simulators and Devices Using Old Xcode?</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Clean your Mac for Xcode’s Users]]></title>
            <link>https://medium.com/swlh/clean-mac-storage-for-xcodes-users-5fbb32239aa5?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/5fbb32239aa5</guid>
            <category><![CDATA[maintenance]]></category>
            <category><![CDATA[macbook]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[storage]]></category>
            <category><![CDATA[cleaning]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Sat, 16 May 2020 10:01:01 GMT</pubDate>
            <atom:updated>2020-05-16T11:12:36.367Z</atom:updated>
            <content:encoded><![CDATA[<h4>How do I save 50 Gb from cleaning Xcode related data</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OF858LpUQdX6nJiIglvy0A.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@tma?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Tianyi Ma</a> on <a href="https://unsplash.com/s/photos/macbook?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>As you may already noticed, Xcode takes a lot of space on your hard drive. From time to time you could see warnings about low storage. Recently I had this problem and my first reflex is finding a script or an app to “clean” my Mac. It helps a bit but not much, since theses apps can only give you “safe” cleaning, typically removing caches data. They don’t “dare” to touch user’s data. After doing some research, I find out 50 Gb to delete from my Xcode related data, and I would like to share with you theses tips. Theses actions are safe because you know what you do.</p><h4>Xcode Caches</h4><p>It’s safe to delete the folder com.apple.dt.Xcode because Xcode can recreate its caches (it could take some time at first relaunch, if Xcode need to re-download something).</p><p>The location of this folder is at ~/Library/Caches/com.apple.dt.Xcode</p><h4>Derived Data</h4><p>Contents of Derived Data folder is generated while Xcode builds your project, so it’s safe to empty it.</p><p>The location of this folder is at ~/Library/Developer/Xcode/DerivedData</p><h4>Xcode Archives</h4><p>Archives could take a lot of spaces. Since you always generate an archive for every release, over time it can cumulate to a big mountain. You can delete them by going to Organizer -&gt; Archives tab -&gt; right-click on the archive you want to delete -&gt; Open in Finder -&gt; remove the .xcarchive file</p><p>The location of this folder is at ~/Library/Developer/Xcode/Archives</p><h4>Xcode Device Support</h4><p>Remove the unneeded iOS’s version support from Xcode can save big space for your Mac (for example, the Device Support folder for iOS 13.1 takes about 3 Gb). This folder is basically needed only to symbolicate crash logs. If your work requires you to support iOS 11 and later, you can safely remove support folder for iOS 10.x and earlier.</p><p>The location of this folder are at ~/Library/Developer/Xcode/iOS DeviceSupport/</p><h4>Simulator Data</h4><p>Simulator’s user data can consume a lot of space. When you want to empty user’s data from a simulator, the official way is to use “Reset Content and Settings” option in Setting app on Simulator. But if you get tired of doing it one by one, you can empty the folder ~/Library/Developer/CoreSimulator Another handy command line xcrun simctl delete unavailable to delete unavailable simulator.</p><h4>Additional Simulators</h4><p>Sometimes you need to download additional simulator of older iOS versions to test your apps. But when you no longer need those simulators, it’s good idea to get rid of them. A simulator takes approximately same size as the iOS.</p><p>The location of this folder are at /Library/Developer/CoreSimulator/Profiles/Runtimes (be careful, the path is <strong>/Library</strong>, not ~/Library)</p><p>I hope theses tips help you to get some extra storage for your Mac. All the tips mentioned in this story are safe, because even you accidentally deleted something you still need, you can be able to regenerate or re-download it. Enjoy cleaning!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5fbb32239aa5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/clean-mac-storage-for-xcodes-users-5fbb32239aa5">Clean your Mac for Xcode’s Users</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Location Permission in iOS 13]]></title>
            <link>https://medium.com/swlh/location-permission-in-ios-13-f9e10917c05e?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/f9e10917c05e</guid>
            <category><![CDATA[wwdc]]></category>
            <category><![CDATA[location]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[permission]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Fri, 15 May 2020 10:01:01 GMT</pubDate>
            <atom:updated>2020-05-15T14:20:59.808Z</atom:updated>
            <content:encoded><![CDATA[<h4>How to request properly “Always Allow” permission</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DldDquFurODuwp_6UFTKgA.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@samuelfoster_co_uk?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Samuel Foster</a> on <a href="https://unsplash.com/s/photos/gps?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>In iOS 13, Apple made a big changes in location permission’s behaviour, especially for “Always Allow” permission. As I have been working full time on a location tracking app since 3 years, I encountered a big challenge and learned a lot from it when supporting iOS 13. In this story, I would like to share my experience when dealing with “Always Allow” request, and how iOS 13.4 brought a big improvement for user experience (though it looks like a workaround) to this request.</p><p><em>Note</em>: I assume that audience knows implementing CoreLocation’s permission and functionality. In this story, I discuss only behaviour aspect, this is not a coding tutorial.</p><h4>Summary of permission’s behaviour</h4><p>In the code, developers can request two types of permission: “When in use” (requestWhenInUseAuthorization) and “Always Allow” (requestAlwaysAuthorization). In iOS 13, whichever option we use, we get this system popup:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/178/1*18bLjEPkpXwbFtwS-inSDQ.png" /></figure><p>This popup uses NSLocationWhenInUseUsageDescription string in the message. As you can see, even you request for “Always Allow”, this option is not available to choose anymore.</p><p>If user selects “Don’t Allow”, in the app and in the iOS Setting, we get <em>.denied </em>permission. This is a straightforward case to handle.</p><p>If user selects “Allow Once”, in the app we received .authorizedWhenInUse permission, and “Ask next time” in the iOS Setting. This option is new in iOS 13, and it replace the “Always Allow” option. If user selects this option, when restarting the app, both in app’s and iOS Setting’s permission status change back to .notDeterminated<em> </em>so we can request again the location permission.</p><p>If user selects “Allow While Using App”, well, this is the confusing part since the behaviour is different between requesting “When in Use” and “Always Allow”, and between iOS versions.</p><p>In case app requests “When in Use”, this choice “Allow While Using App” gives both app and system setting the .authorizedWhenInUse permission. It’s good since app get what it’s supposed to get.</p><p>In case app requests “Always Allow”, this choice “Allow While Using App” gives app <strong>.authorizedAlways </strong>and system setting <strong>.authorizedWhenInUse</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*h89-JrrcztEbGd4Pp_BARQ.png" /><figcaption><em>authorizedWhenInUse in app ; authorizedWhenInUse in setting (source: </em><a href="https://developer.apple.com/videos/play/wwdc2019/705/"><em>WWDC 2019</em></a><em>)</em></figcaption></figure><p>You may ask “Why are they different? Is it a bug?”. Well, you’re not alone. This is what Apple called deferred permission, or provisional permission. Whatever we call it, it means the real “Always Allow” permission will be shown later, at the time decided by iOS system.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*izKE6R7mdC3IMPWWocTbsQ.png" /><figcaption>Allow Always confirmation comes later (source: <a href="https://developer.apple.com/videos/play/wwdc2019/705/">WWDC 2019</a>)</figcaption></figure><p>In real life, user can expect to see the popup below a few days later:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/180/1*M4OmrnCRbhzYXBwAVlQ9YQ.png" /></figure><p>Actually, this is the real popup for “Always Allow”, which uses your NSLocationAlwaysAndWhenInUseUsageDescription string as message. If user selects “Change to Only While Using”, both app and setting get the permission .authorizedWhenInUse. Otherwise, if user selects “Always Allow”, then both app and setting now get the “true” .authorizedAlway<em>s</em>.</p><p>This new behaviour in iOS 13 imply frustration for tracking app’s designers. Since app get the “pretended” Always Allow permission at the beginning, user may accidentally “Change to Only While Using” on second confirmation, and disrupt app’s functionality. Many companies had to design a force setting permission screen in their apps to redirect user to location permission in iOS Setting and let users manually choose the correct one.</p><h4>Improvement for iOS 13.4</h4><p>Since iOS 13.4, it seems like Apple realized that it need some user experience improvement. So, as I mentioned at the beginning, they decided to allow developer to show the second popup immediately. But it doesn’t come with a straightforward implementation. As stated in requestAlwaysAuthorization documentation in Xcode 11.4:</p><blockquote>An application which currently has “when-in-use” authorization and has never before requested “always” authorization may use this method to request “always” authorization one time only</blockquote><p>In fact, this means, for a fresh user (never gives any location permission before in app), we must show firstly a “When in Use” request. If user gives “When in Use” permission, then we make the “Always Allow” request to pop the second one. You can inspire from the code below:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/45151bde7dd1dc1512007157f12cdec7/href">https://medium.com/media/45151bde7dd1dc1512007157f12cdec7/href</a></iframe><p>Simple, right? In iOS 13.4, we can just setup a closure, so when user answer the first popup, we can detect if they give the “right” choice and if so, show the “Always Allow” request.</p><p>Using this code, we will get the desired result:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OqjM3EDpWqvCIImtBCwR1w.png" /><figcaption>Happy path’s sequence when running this code on iOS 13.4.</figcaption></figure><h4>Where to go from here?</h4><p>If you want to understand deeper in Core Location changes in iOS 13, I suggest the excellent presentation from WWDC 2019: <a href="https://developer.apple.com/videos/play/wwdc2019/705/">What’s New in Core Location</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9e10917c05e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/location-permission-in-ios-13-f9e10917c05e">Location Permission in iOS 13</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CI/CD automation for mobile development from scratch (part 2)]]></title>
            <link>https://medium.com/swlh/ci-cd-automation-for-mobile-development-from-scratch-part-2-1de27443ff21?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/1de27443ff21</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[fastlane]]></category>
            <category><![CDATA[continuous-deployment]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Mon, 11 May 2020 10:01:00 GMT</pubDate>
            <atom:updated>2020-05-15T19:17:45.920Z</atom:updated>
            <content:encoded><![CDATA[<h3>CI/CD Automation for Mobile Development from Scratch (Part 2)</h3><h4>Tutorial on how to implement Fastlane to automated your mobile development tasks</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*V6-JM6qz7FFjCXjLQLXNlw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@osmanrana?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Osman Rana</a> on <a href="https://unsplash.com/collections/1255444/life-in-the-fast-lane?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>In previous parts of this tutorial, we talked about how automation is powerful, even essential to our daily work:</p><p><a href="https://medium.com/swlh/why-does-ci-cd-automation-become-essential-in-mobile-development-da6802eb6988">Why does CI/CD automation become essential in mobile development?</a></p><p>In part 1 of “CI/CD automation for mobile development from scratch”, we talked about setting up <a href="https://app.bitrise.io/referral/70497388555a18c4">Bitrise</a>, connect it with your repo, and create a workflow to detect and test all our pull requests:</p><p><a href="https://medium.com/swlh/ci-cd-automation-for-mobile-development-from-scratch-part-1-d2b41705afa9">CI/CD automation for mobile development from scratch (part 1)</a></p><p>We also mentioned using <a href="https://fastlane.tools/">Fastlane</a> will level up our ability. Since you are here reading this, we assume that this automation tool interest you :].</p><p>Fastlane is an amazing tools to make your CI/CD workflow truly versatile and powerful. It provides a rich set of preset actions for boring mobile tasks, so you don’t have to manually do it. It is also easy to integrate many Ruby gems or other scripts with Fastlane to handle specific tasks.</p><p>In this tutorial, we would like to show how Fastlane support local process as well as integrate with existing cloud CI/CD. We will write a simple flow that help downloading dSYM zip file from iOS App Store Connect and uploading it to Firebase Crashlytics. Crash Analytic tool like Crashlytics is important to monitor our app’s stability. Since dSYM is essential data in order to make Crash Analytics tools works properly, this workflow is a typical step in the release process. Finally, we will talk about some inspiring automated tasks that you could begin with.</p><p><strong>Prerequisites: </strong>I assume that Fastlane was setup correctly on your local. If not, follow <a href="https://docs.fastlane.tools/getting-started/ios/setup/">Fastlane setup guide for iOS</a></p><h3>Create the lane</h3><p><strong>First step</strong>: now we open our Fastfile with a text editor, or Xcode. We prepare a lane like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/21ae56fffd0154819f04edc0f52e092e/href">https://medium.com/media/21ae56fffd0154819f04edc0f52e092e/href</a></iframe><ul><li>desc<em>: </em>description of the lane.</li><li>lane: similar to a function, it goes with lane name upload_dsym_appstore and options (input parameter list)</li><li>UI.message: to print out the text to terminal console</li><li>end: end of the lane</li></ul><p>Now we can open the Terminal and run the command line:</p><p>fastlane upload_dsym_appstore</p><p>We must see the output text ‘Hello World’. It seems nothing for now, but this is the most important milestone in implementing Fastlane. It proves that we actually make it worked, like we made in our first iOS apps with a label ‘Hello World’ in a white background ;]</p><p><strong>Second step</strong>: Fastlane provides many <a href="https://docs.fastlane.tools/actions/">preset actions</a>. At this step, we will implement preset action to download dSYM: download_dsyms. Search this action in that preset list and click on the action to get this <a href="https://docs.fastlane.tools/actions/download_dsyms/">download_dsyms action’s documentation</a>. Replace <em>UI.message</em> with the download_dsyms.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ced133f7018d023970d8ad07c61e8f32/href">https://medium.com/media/ced133f7018d023970d8ad07c61e8f32/href</a></iframe><p>username: your App Store Connect’s email account</p><p>app_identifier: the bundle ID of target app</p><p>team_id: I have hard time figure out this magic ID since it is not the team ID we can find on Apple Developer website. To get this, we have to log in our team’s account on appstoreconnect. Then open this website: <a href="https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/ra/user/detail">https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/ra/user/detail</a></p><p>It gives us a JSON. Now look through <em>associatedAccounts </em>array<em> </em>to find <em>contentProviderId </em>that match our team’s <em>name</em>.</p><p>version: specify the app’s version we want to download dSYM. Use “latest” if we want to download the most recent app’s version dSYM.</p><p>Run this code and we can expected to see a .zip file that contains our app’s dSYM</p><p><strong>Third step</strong>: now just upload them all to Firebase Crashlytics. Go back to that <a href="https://docs.fastlane.tools/actions/">action list</a> again, and search for action upload_symbols_to_crashlytics. Now the code looks like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/caf01868d25803bca13c4fa095a85885/href">https://medium.com/media/caf01868d25803bca13c4fa095a85885/href</a></iframe><p>Here we list all the zip file and loop through them. The action upload_symbols_to_crashlytics<em> </em>requires only the file path and the Crashlytics token. This action uses <em>upload-symbols</em> script in Crashlytics framework to upload dSYM, so we need to had Crashlytics installed by Cocoapods.</p><p>The last line clean_build_artifacts is to clean all files, including the zip file.</p><p>Run the code and enjoy seeing the lane doing all the hard work for us.</p><h3>Integrate with cloud CI/CD</h3><p>Now we have a working lane, that works perfectly on our local. All we need to do is to execute the command fastlane upload_dsym_appstore in Terminal. As an excellent developer, you could ask: Could we even be lazier? What about make it completely automatic, so we don’t even have to think about it?</p><p>If you read the <a href="https://medium.com/swlh/ci-cd-automation-for-mobile-development-from-scratch-part-1-d2b41705afa9">part 1</a> of this series, you know that it’s feasible and you may even have a clear idea how to do that. If you didn’t read it, just take a look on the details how to implement cloud CI/CD quickly and come back here later. Here we can go straight the to the final result, which looks like this on <a href="https://app.bitrise.io/referral/70497388555a18c4">Bitrise</a>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5-jJZp_ck8RNqNoT9AIywg.png" /></figure><p>The flow is very intuitive and minimalism:</p><ol><li>Clone the repo</li><li>Run pod install: this step is needed because we need to set up crashlytics framework and have <em>upload-symbols</em> script available</li><li>Add step <em>fastlane</em> here and make it run the lane we just create: fastlane upload_dsym_appstore</li><li>(Optional) Slack to our team channel to get confirmation.</li></ol><p>Now we have two ways to automatically trigger it:</p><ol><li>If we have a release workflow already, which send builds to App Store, it makes sense to add this workflow at the end of the release one. The inconvenient side effect of this solution is that sometime App Store take many hours to processing a build, so it will makes our workflow stuck there doing nothing for a long time.</li><li>Or we can schedule to upload dSYM on a specified schedule, for example every midnight. The inconvenience of this solution is that most of our trigger is for nothing because we only need to upload dSYM once for a new build. But well, it doesn’t harm anything since it runs during the night, where our work traffic is light.</li></ol><h3>Release flows</h3><p>Uploading dSYM is a typical flow followed the release workflow. Fastlane makes it feasible to integrate it with your current release process and make it automatic. You can find below a popular release flow used in some companies and some hints on how realizing it with Fastlane.</p><ol><li>Create release branch base on your development branch: in Fastfile, using sh command to run shell command. We use shell command to interact with git functions. Example: sh(“git pull”, log: false)<em> </em>will pull all remote changes from your current branch.</li><li>Execute release_build workflow on Bitrise thanks to sh “curl …”<em>. </em>Use this <a href="https://api-docs.bitrise.io/">Bitrise’s API documentation</a></li><li>That release_build workflow run the lane release_app_store on Fastfile. This lane will archive, sign the build, update certificates and provisionning profile if needed, then finally send the build to App Store. All these functions can be found in <a href="https://docs.fastlane.tools/actions/">Fastlane’s documentation</a></li><li>Bump current app’s minor version on a branch from development branch thanks to a <a href="https://github.com/CocoaPods/Xcodeproj">Cocoapods’s Ruby public library Xcodeproj</a>. Push it.</li><li>Create a pull request to merge this bumping branch to development branch. Here’s <a href="https://developer.atlassian.com/bitbucket/api/2/reference/resource/">Bitbucket API’s documentation</a></li><li>Waiting for App Store build processing finished and upload dSYM.</li></ol><h3>Where to go from here?</h3><p>As an iOS Engineer, I have fun time learn and implement our CI/CD tools. You may enjoy it too.</p><p>Every team has different needs and capacity. Before implementing the workflows, we should discuss with our team to figure out our development strategy, our release strategy, and our special business needs.</p><p>Here a non-exhaustive list of flows that you can inspire your team:</p><ol><li><a href="https://medium.com/swlh/ci-cd-automation-for-mobile-development-from-scratch-part-1-d2b41705afa9">Merge check</a>: run unit tests to validate all the branch-to-merge. This lane is the simplest automated task to implement, but it gives big improvement on development’s quality since it gives early warnings of bugs or compilation failed.</li><li>Deploy debug builds: could be run at the merge, or schedule to run a few times a day. This lane archive and send builds to a Beta distribution services, like Firebase App Distribution. This lane automatically gives QA access to the most recent code changes.</li><li>Release builds: typically run when release branch create, or have new pushes. This lane archives, tests and sends build to App Store, waiting to release. This flow can end up with the workflow of uploading dSYM on iOS side.</li><li>Testing lane: typically run during the night. This run through all your unit tests, UI tests, performance tests. Depending on the size of your tests, it could takes hours to finished them, that’s why it’s recommended to schedule to run it during night.</li><li>Sync app’s text: typically run during the night. This lane download all copy-related Confluence page, or Excel files, parse them and generate updated <em>.strings</em> file for our apps. Finally, it create a pull request. So next morning, we can just check and merge this branch to have synced strings. This flow is very efficient if you have a separated marketing/writer/services team working on texts.</li></ol><p>After years of developing automation tasks, my team had a rich set of automatic flows, which allowed us to truly focus on what we love to do: developing mobile apps. By investing some time on this, you could also save a lot of time to work on something you love: developing mobile apps. Let the robot handle the boring tasks!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1de27443ff21" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/ci-cd-automation-for-mobile-development-from-scratch-part-2-1de27443ff21">CI/CD automation for mobile development from scratch (part 2)</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CI/CD automation for mobile development from scratch (part 1)]]></title>
            <link>https://medium.com/swlh/ci-cd-automation-for-mobile-development-from-scratch-part-1-d2b41705afa9?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/d2b41705afa9</guid>
            <category><![CDATA[continuous-deployment]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[bitrise]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Fri, 08 May 2020 10:01:00 GMT</pubDate>
            <atom:updated>2020-05-15T19:08:48.182Z</atom:updated>
            <content:encoded><![CDATA[<h3>CI/CD Automation for Mobile Development from Scratch (Part 1)</h3><h4>Tutorial on how to implement a Bitrise pipeline in less than one hour</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SABnYfT-DtAuwGOgkqs79g.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@sortino?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Joshua Sortino</a> on <a href="https://unsplash.com/s/photos/automation?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>This story guide you to implement the CI/CD cloud service in less than one hour. CI/CD is one of the best practices for mobile development teams to implement:</p><p><a href="https://medium.com/swlh/why-does-ci-cd-automation-become-essential-in-mobile-development-da6802eb6988">Why does CI/CD automation become essential in mobile development?</a></p><p>It is also an agile methodology best practice, as it enables mobile development team to focus on meeting business requirements, code quality, and security because other tasks are automated.</p><p>In this tutorial, I would like to introduce <a href="https://app.bitrise.io/referral/70497388555a18c4">Bitrise</a>. Bitrise is a leading CI/CD cloud platform for mobile. The setup of workflows using in this platform is easy and intuitive. As a mobile developer, we can setup some basic workflows in just a few hours. In this story, you will be presented how to setup a typical workflow: merge check for a Pull Request. The main objective of this workflow is to validate the pull request created by a developer in our team, before merging it in development branch. This example workflow will run all tests (UI tests, unit tests, …) enabled in the project’s test target.</p><p><strong>Prerequisites: </strong>in this tutorial, I assume that you already had a <a href="https://app.bitrise.io/referral/70497388555a18c4">Bitrise’s account</a> and was given all necessary permissions to create and modify a Bitrise’s app. If you don’t have an account, you can create one for free. A Bitrise’s app can be quickly created from Dashboard -&gt; Add new app -&gt; then follow the guide to connect your repo to the app. Though this tutorial’s objective is to merge check an iOS build, it’s still relevant for Android developers to look at and learn the set up process.</p><h3>Setup Bitrise app</h3><p>To create this merge-check workflow, firstly go to the app dashboard, then click on workflow tab to open Workflow manager.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4rxJeITg0e7Y6vikXUDU8Q.png" /></figure><p>You will see workflow manager displayed like below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o1XU-KeJtZsMmqzP9-mM6Q.png" /></figure><p>On the first row, it displays all configurations needed for an iOS build:</p><ol><li>Workflows: this is where we can see and manage all workflows. On the second line, there are options we can use to switch, create, add existing, and rearrange workflows. When we created this app, by default, Bitrise provide us a “primary” workflow, which is used to archive iOS apps. Now, click on “+ Workflow” and give it a name (in this tutorial I will use “DemoWorkflow”) by cloning the “primary”. We now have our first baby workflow. For the sake of our tutorial, we remove all preset steps, so we can created them from scratch.</li><li>Code Signing: this is where we can safely keep certificates and provisioning profiles. At the top of this tab, we will see the guide about using a script to export our local certificates and provisioning profiles on Bitrise. In this tutorial, we don’t need to setup them, since the tests will run only on simulator. Later, when we need to archive the build to export it to Beta tools or App Store, we definitely need to setup this.</li><li>Secrets and Env Vars: basically theses are stored parameters we need to use in the workflows. “Secrets”, well, mean confidential ones. Parameters saved here will be encrypted and will never be exposed in the logs. Info stored will be displayed as ***** in this section and in the logs. This is typical place to save passwords, token…etc. On the other hand, “Env Vars”, stored regular variables. This is where our stored parameters like: scheme name, project path, app version, …etc. Info stored here are exposed to all of our team members.</li><li>Triggers: this is where we create rules on how to trigger a workflow. Bitrise provide 3 ways of triggering: Pull request, Push and Tagging. In this tutorial, we want to tests a pull request, so check the Pull Request tab, click on “+ Add Trigger” and fill the source, destination and workflow, we will get something like this:</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zlezp3MC6sgMTf1SlhXjCA.png" /></figure><p>This config mean when there’s a pull request from any branch, toward branch ‘develop’, it will trigger the workflow ‘DemoWorkflow’. Do ‘Save’ (Cmd + S) now. In addition of this triggers, we can also schedule a workflow at specified time, but it will be presented a bit later.</p><p>5. Stack: this is where we specify Xcode and Mac OS version to run our workflow. Select the correct one for your project.</p><p>6. bitrise.yml: this is the configuration file that sum up our whole setup in this Bitrise’s app. We may need to backup this file from time to time, just in case we need to rollback.</p><h3>Setup Pre-Merge workflow</h3><p>Now, it’s time for real work …:] Actually, there’s not much left to do here, we will finish it in 5 minutes. So, let’s switch back to Workflow tab. We will design the flow like this: get the repo, install pod or Carthage if needed, run tests, and that’s it.</p><ol><li>Cloning the git repo on the pull request’s branch: if your repo is private, add the step SSH Key (click on the “+” sign, and search for keyword ‘SSH’). This will activate the SSH key you generate when creating this Bitrise’s app. Then we add the step Git Clone repository. Normally, this’s all correct already, since Bitrise is smart enough to pre-fill all the information needed like Git URL, branch name (which is always Source branch)</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*lUadlKKMCJevmUFxnNSQ1A.png" /><figcaption>At this point, we will see something like this. You don’t need the first step ‘Activate SSH Key’ if your repo is public</figcaption></figure><p>2. Depend on the project, you may need to do pod install, or run Carthage. Do add step using keyword ‘Cocoapods’ or ‘Carthage’. Again you may not need to specify anything in the step’s config (in case of Cocoapods, Bitrise will setup pod repo and do pod install by default)</p><p>3. Now we have the project setup, we need to run tests. To do so add the step ‘Xcode Test’. In this step we should check if all pre-filled parameters are actually what we want, for example: the scheme, the iDevice to run tests, the iOS version…</p><p>At this point, we’re proud to say our mission was archived. This workflow will tests our app when there’s a pull request toward our develop branch. In effect, we can stop here, save our changes, and make a pull request to see if everything connects correctly together. Our workflow now will look similar to below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*lq8zz43YQ9z338KjQUUpeA.png" /></figure><p>It’s worth to mention that some cloud repo, like Bitbucket, integrates Bitrise seamlessly, so we will see a green checkmark once workflow finish successfully:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jUoqNIvp5Z8qDQRSntIwJA.png" /></figure><p>Below is two popular extra steps that make our CI/CD fancier ^^</p><p>4. Export apps, logs or artifacts: this step will export everything generated by the previous steps: logs, unit tests reports, archives, IPA, dSYM… so we can download it for review. Once implement this, we will get all the stuffs in the Apps &amp; Artifacts tab:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u4rkbusKujCdsW7oUr_ovA.png" /></figure><p>5. Send success/fail message to Slack: we may not want to go check our Bitrise or Git repo from time to time to see if the tests passed. By sending message to our communication tools, we passively and immediately notified workflow’s result. So go search for ‘Slack’ step. This step required our Slack’s Wekhook URL or Slack’s API token, which is sensitive so we should stored them in ‘Secrets’</p><p>The final workflow now look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*bK9scSl_YPYU7NI4EfOCeg.png" /></figure><h3>Some helpful tips</h3><p><strong>It’s better to use environment variables</strong> in our workflow, rather than hard-code ones. When all ENV VARS in one place, it’s easier to review our configurations.</p><p><strong>Variables should avoid Bitrise prefix</strong>: almost all steps in Bitrise generate output variables which have Bitrise prefix. Do not use this prefix help you avoid confuse when reading step’s config and possible conflicts.</p><p><strong>Create common workflow steps</strong>: as you may notices, a workflow can be combined of multiple other workflows. If we intend to create many workflows for different scenarios, we should group the common steps in one workflow. For example, every workflow need firsts steps similar to SSH-&gt; Git clone -&gt; Pod install. So those steps could be set up in a workflow name ‘PreBuild’.</p><p><strong>Use Pull, Push cache steps</strong>: Bitrise provide Pull/Push steps, which allow to pull cache builds from previous build, and push the current cache when workflow done. It improve considerably workflow’s build time.</p><p><strong>Use option ‘Run if previous steps failed’</strong>: every step has this toggle. Use it when we feel convenient. For example, we don’t need to export apps build if previous step archiving app failed. It helps saving time since we don’t have to spend time in running a step for nothing.</p><p><strong>Enable rolling builds</strong>: activate all theses options in App’s Settings. It will cancel all previous builds for Pull Requests/Pushes to the same branch, so we avoid duplicated worked</p><p><strong>Schedule workflow</strong>: in addition of trigger on events, we can schedule workflow to run at a specific time. At the app’s dashboard, click on “Start/Schedule a build” -&gt; toggle ON “Schedule this build” and setup the day, time and the workflow we want to run. This feature is mostly use for time consuming tasks, like UI tests, performance tests, TestFlight build delivery. Since it’s time consuming, we don’t want them to run during our workday, because they will create traffic jams without much adding value. We should make our CI/CD works while we sleep ;)</p><h3>Where to go from here?</h3><p>There are still many awesome step features to discover. What we did in this tutorial is just a scratch on the surface of what CI/CD can help us improving our daily performance. Take your time to discover them and try them. That may help you generate some ideas on how to facilitate your daily tasks’s.</p><p>Cloud CI/CD is a great start in enabling automation in our development process. In fact, my team use this tool alone during two first years and it improves a lot our work’s velocity, quality and happiness. But it turns out that CI/CD level up to full power and versatility only when combining with Fastlane. <a href="https://fastlane.tools/">Fastlane</a> is an open source automation app that allows you to write customized tasks, defined your own action’s rules, and sync all our work platforms seamlessly. To name a few:</p><ul><li>Capture screenshots automatically</li><li>Distribute beta builds to multiple Beta testing services (Testflight, Firebase App Distribution, Hockey…)</li><li>Publish multiple apps at once with a single command line</li><li>Automatic code signing for iOS</li><li>Update test, build, delivery info on your JIRA ticket</li><li>All of these happen while we’re working on something else</li></ul><p>Basically Fastlane is able to sync with every platform that provide an API, and his abilities is limited only by our imagination ;]</p><p>If you’re interested to know more about Fastlane, this is the part 2 of this tutorial:</p><p><a href="https://medium.com/@nqtuan86/ci-cd-automation-for-mobile-development-from-scratch-part-2-1de27443ff21">CI/CD automation for mobile development from scratch (part 2)</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d2b41705afa9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/ci-cd-automation-for-mobile-development-from-scratch-part-1-d2b41705afa9">CI/CD automation for mobile development from scratch (part 1)</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why does CI/CD automation become essential in mobile development?]]></title>
            <link>https://medium.com/swlh/why-does-ci-cd-automation-become-essential-in-mobile-development-da6802eb6988?source=rss-3a776011c59a------2</link>
            <guid isPermaLink="false">https://medium.com/p/da6802eb6988</guid>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[mobile-development]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[continuous-deployment]]></category>
            <dc:creator><![CDATA[Quang NGO]]></dc:creator>
            <pubDate>Mon, 04 May 2020 10:01:01 GMT</pubDate>
            <atom:updated>2020-05-15T18:53:10.067Z</atom:updated>
            <content:encoded><![CDATA[<h3>Why does CI/CD Automation Become Essential in Mobile Development</h3><h4>6 reasons to make your mobile development’s workflow automated</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YaoSCJRDq85UxlcsG24pMQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@_imkiran?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Sai Kiran Anagani</a> on <a href="https://unsplash.com/s/photos/automation?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Continuous integration (CI) and continuous delivery (CD) is a set of operating principles, and collection of practices that enable mobile development teams to deliver code changes more frequently, reliably and automatically. The implementation is also known as the CI/CD pipeline.</p><p>From almost a decade working as a software engineer, I learned that this is one of the most vital tools we need in the team. The bigger the mobile team we have, the more important this tools become.</p><h3>Why should we use CI/CD?</h3><p>CI/CD is one of the best practices for mobile development teams to implement. It is also an agile methodology best practice, as it enables mobile development team to focus on meeting business requirements, code quality, and security because other tasks are automated.</p><h4><strong>Continuous testing</strong></h4><p>Automated testing is one of the best benefit of CI. Developer can setup CI tool in a way that once there is an event, like pull request creating, pushing on a branch, or tagging on the repo, the tool will checkout the repo, make the build, and run various tests. This step ensures that developers only merge or deliver code after theses tests passed on the code changes.</p><h4><strong>Enable more frequent deployments</strong></h4><p>In short, CI pipeline builds and alerts developers if their changes failed any tests (unit tests, UI tests, performance tests). CD is the automation that delivers changes to Beta services infrastructure and executes additional tests.</p><p>CI/CD pipelines are designed for businesses that want to improve applications frequently and require a reliable delivery process. Once in place, it enables teams to focus on the process of app development and less on the system details of delivering it to Beta distribution or App Store.</p><p>CI/CD is a devOps best practice because it addresses the misalignment between developers who want to push changes frequently, with product owner that want stable applications. With automation in place, developers can push changes more frequently. Product owner see greater stability because environments have standard configurations, there is continuous testing in the integration process, local environment variables are separated from the application.</p><h4><strong>Great ability to attract and retain talent</strong></h4><p>Engineers that can focus on what they are best at will be happier and more productive, and that has far-reaching impact. Turnover can be expensive and disruptive. A good CI/CD strategy means engineers can work on important projects and not worry about time-consuming manual tasks. They can also work confidently knowing that errors are caught automatically, not right before deployment. This kind of cooperative engineering culture inevitably attracts talent.</p><h4><strong>Higher quality code and operations</strong></h4><p>Developers can focus on development. Bad code rarely makes it to production because testing is automated. Developers can focus on the code rather than the production environment or manual stuffs, and operations does not have to feel like a barrier. Both sides can work to their strengths, and automated handoffs make for seamless processes.</p><h4><strong>Versatile and Powerful</strong></h4><p>Beside the main CI/CD functions (build, test, integrate and delivery), theses tools are able to interact with almost all others working platform, to name a few: Slack, version control repository’s cloud server (Bitbucket, Github…), JIRA, Confluence, Firebase... Combining with <a href="https://fastlane.tools/">Fastlane</a> automation app, CI/CD lets us automate every aspect of our mobile development and release workflow.</p><h4><strong>Give away little effort on setting up and maintaining, getting big benefits</strong></h4><p>Some companies have operation team, who handle CI/CD pipeline. But if we are a small team of devs, or even individual developer, CI/CD still brings great values and it’s easy to implement. The basic functions of CI/CD can be implemented from scratch in one working day.</p><p>Let’s take an example from <a href="https://app.bitrise.io/referral/70497388555a18c4">Bitrise</a>, a mobile CI/CD platform, here is what I’m able to implement and make it works during a few hours:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/346/1*rsHSZwcSiaT_XIty_51Lnw.png" /><figcaption>Bitrise’s steps to unit test an iOS branch before merging</figcaption></figure><p>We could see the step is intuitive and easy to understand. Basically, the workflow clone the repo, setup iOS certificates, build and unit tests, then finally send the result message to our team Slack channel. Each step require its dedicated parameters like git branch name, URL, Slack’s web-hook token, Slack’s channel name… Once in place, it just works.</p><h3>How to optimize the use of CI/CD?</h3><p>Getting started with CI/CD requires development teams and operational teams to collaborate on technologies, practices, and priorities. Teams need to develop consensus on the right approaches for their business and technologies so that once CI/CD is in place, the team is onboard with following practices consistently.</p><p>Most CI/CD tools let developers kick off builds on demand, triggered by code commits in the version control repository, or on a defined schedule. Teams need to discuss the build schedule base on the size of the team, the number of daily commits expected, and the tasks to execute.</p><h3>What are the tools needed for CI/CD?</h3><p><a href="https://app.bitrise.io/referral/70497388555a18c4">Bitrise</a> is a leading CI/CD cloud platform for mobile (iOS, Android) development. It offers a free plan so it is a good start if we want to try to implement the CI/CD practice. Beside there are Travis CI, Circle CI that could be worth to try.</p><p>A great tool to add to CI/CD cloud platform is <a href="https://fastlane.tools/">Fastlane</a><em>, </em>an automation app<em>. </em>It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing our application. Furthermore, this is the tool we need to make our pipeline truly versatile and powerful. Thanks to Fastlane, you can write the task and programme action’s rule on all working platforms.</p><h3>Where to go from here?</h3><p>This is the first story of my series on CI/CD. I hope this gave you an inspiration on how to bring your mobile team’s performance to the next level. This could be a good time to begin your team’s discussion and implement the basic functionalities of CI/CD.</p><p>On the next articles, I will give details on how-to and best practices. More in-depth analyze of mobile development’s manual tasks and how CI/CD can automate them. It also provide step-to-step guide on how to implement some essentials tasks.</p><p>My first tutorial will be on implementing a useful Bitrise’s workflow to unit test all Pull Request.</p><p><a href="https://medium.com/swlh/ci-cd-automation-for-mobile-development-from-scratch-part-1-d2b41705afa9">CI/CD automation for mobile development from scratch (part 1)</a></p><p>The next one will level up automation to full power by using Fastlane. This tutorial guide you to implement Fastlane to download dSYM from App Store and upload them to Firebase Crashlytics.</p><p><a href="https://medium.com/@nqtuan86/ci-cd-automation-for-mobile-development-from-scratch-part-2-1de27443ff21">CI/CD automation for mobile development from scratch (part 2)</a></p><p>If you are interested in this series, please following me to stay tuned for updates.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=da6802eb6988" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/why-does-ci-cd-automation-become-essential-in-mobile-development-da6802eb6988">Why does CI/CD automation become essential in mobile development?</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>