<?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 Agam Mahajan on Medium]]></title>
        <description><![CDATA[Stories by Agam Mahajan on Medium]]></description>
        <link>https://medium.com/@agam.mahajan?source=rss-ede4f93130a7------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*_Mi0pnJ61vI_PAN314pc0Q.jpeg</url>
            <title>Stories by Agam Mahajan on Medium</title>
            <link>https://medium.com/@agam.mahajan?source=rss-ede4f93130a7------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 13 Nov 2026 15:46:30 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@agam.mahajan/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[Mobile DevOps Journey | Evolving Mobile Development at Swiggy with Bitrise | Episode 1]]></title>
            <link>https://medium.com/swiggy-bytes/mobile-devops-journey-evolving-mobile-development-at-swiggy-with-bitrise-episode-1-970442617654?source=rss-ede4f93130a7------2</link>
            <guid isPermaLink="false">https://medium.com/p/970442617654</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[swiggy]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Agam Mahajan]]></dc:creator>
            <pubDate>Wed, 10 Apr 2024 15:09:41 GMT</pubDate>
            <atom:updated>2024-04-11T08:39:11.546Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jTTkfq1rkGyxFUwGQPaPiA.jpeg" /></figure><h3>Introduction:</h3><p>Swiggy, India’s foremost food, grocery, and dining platform, has consistently led the charge in innovation, relentlessly pursuing ways to elevate user experiences and optimize operations. At the heart of this endeavor lies our mobile application, catering to millions of users each day. Recognizing the imperative to evolve our mobile development process to sustain our competitive advantage, this article explores Swiggy’s Mobile team’s transition from an in-house CI/CD setup to <a href="https://bitrise.io/">Bitrise</a>, a leading CI/CD platform. This shift marked the inception of our Mobile DevOps journey, aimed at fostering efficiency, collaboration, and quality throughout the development lifecycle.</p><h3>Mobile DevOps — Why it Matters?</h3><p><strong>1. Speedy Delivery:</strong> Mobile DevOps enables rapid development cycles, ensuring swift updates and feature releases to stay ahead of the competition and meet user demands promptly.</p><p><strong>2. Collaborative Workflow</strong>: By fostering teamwork and breaking down silos between development, operations, and QA teams, Mobile DevOps promotes seamless collaboration towards a common goal of delivering high-quality apps.</p><p><strong>3.</strong> <strong>Enhanced Quality and Reliability</strong>: Automated testing and continuous integration practices ensure that code changes are thoroughly validated, resulting in fewer defects and a more reliable user experience.</p><p><strong>4. Seamless Deployment:</strong> DevOps principles automate deployment processes, facilitating smooth updates to production with minimal downtime and disruption to users.</p><p><strong>5. Continuous Improvement:</strong> A culture of continuous improvement underpins Mobile DevOps, allowing teams to analyze feedback and performance metrics to refine their processes and deliver better mobile experiences over time.</p><h3>The Need for Change:</h3><p>At Swiggy, we employed an in-house CI/CD setup managed through Jenkins</p><blockquote><strong>Android</strong>: EC2 instance of Jenkins<br><strong>iOS</strong>: On-premise machine of Mac Pro</blockquote><p>It effectively supported our operations for numerous years, granting us control and flexibility within the development pipeline. Nevertheless, with the expansion of our mobile application in complexity, user engagement, and team size, we encountered issues regarding scalability and maintenance.</p><p>Several significant challenges arose:</p><ul><li>Insufficient concurrency/parallelism resulting in prolonged wait times.</li><li>Frequent instances and machine outages.</li><li>Manual upgrades.</li><li>Integration complexities with third-party extensions.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/664/1*0lZajpR90aE1Ur5-UKFRNw.png" /></figure><p>Manual intervention proved necessary at different junctures throughout the development lifecycle, causing bottlenecks and impeding the timely delivery of updates to users.<br>The mobile technology landscape at Swiggy has continuously expanded, with support now extended to numerous tech stacks overseen by distinct teams across our diverse app offerings.<br>Acknowledging this evolution, we identified the necessity for a more resilient, automated solution to expedite our development process and guarantee the delivery of high-quality releases.</p><h3>Evaluation:</h3><p>We conducted a comprehensive assessment of various platforms including Bitrise, GitHub Actions, and Dedicated EC2, focusing on the following criteria:</p><ol><li>Faster builds: Prioritizing speed of execution.</li><li>Parallelization of builds: Minimizing wait times.</li><li>Latest Tech Stack support: Ensuring compatibility with M1 for iOS and the latest Android versions.</li><li>Stability: Aim for negligible downtime.</li><li>Integrations: Supporting third-party extensions such as Slack, GitHub, and AppstoreConnect.</li><li>Support, Observability, and Insights: Enhancing overall efficiency through robust support and insights.</li><li>Cost: Ensuring the platform’s benefits in terms of developer time saved and improved efficiency outweigh the platform’s cost.</li></ol><p>Following a thorough evaluation, we opted to integrate Bitrise into our existing infrastructure. Bitrise’s user-friendly interface, extensive feature set, and seamless integrations with popular tools and services rendered it the optimal choice for our requirements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/689/1*AzGFjtYTjGtZk3VyzN1aDg.png" /></figure><h3>Integration:</h3><p>Harnessing Bitrise’s capabilities, we embraced a more agile and efficient development approach. Automated builds, tests, and deployments became standard practice, slashing manual overhead and facilitating expedited delivery of features and bug fixes. With Bitrise handling the heavy lifting, developers reclaimed valuable time to concentrate on coding, enhancing productivity across the board.</p><h3>Key Benefits Realized:</h3><ol><li>Faster Build Times: Utilizing Bitrise’s latest tech stack resulted in a 40–50% improvement in build pipelines.</li><li>Increased Efficiency: The parallelization capability reduced waiting time by 70–80%.</li><li>Improved Quality: Automated testing and continuous integration facilitated the integration of UT and lint checks reports on GitHub, enhancing code quality.</li><li>Enhanced Maintainability: Over the past year with Bitrise, we’ve experienced minimal downtime, contributing to easier maintenance.</li><li>Insights: Bitrise’s insightful capabilities allow us to monitor build times, and credit usage, set thresholds, and continually enhance our processes.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3nr0snVFKk00yZwHX2eB1A.png" /></figure><h3>Future Outlook:</h3><p>As we advance on our Mobile DevOps journey with Bitrise, our dedication to innovation and excellence in mobile app development remains unwavering. Our future endeavors include delving into additional features such as build cache, release management, and integrations provided by Bitrise. By harnessing these capabilities, we aim to further optimize our development process and proactively address evolving market demands, ensuring that we stay at the forefront of mobile app development.</p><h4>Acknowledgments</h4><p><a href="https://medium.com/u/4bb1b7609dfe">Mayank Jha</a> <a href="https://medium.com/u/2f0dfadbf951">Farhan Rasheed</a> <a href="https://medium.com/u/cf5af6a99299">Garima Bothra</a> <a href="https://medium.com/u/39cccc0dac1c">Minal Arora</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=970442617654" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swiggy-bytes/mobile-devops-journey-evolving-mobile-development-at-swiggy-with-bitrise-episode-1-970442617654">Mobile DevOps Journey | Evolving Mobile Development at Swiggy with Bitrise | Episode 1</a> was originally published in <a href="https://medium.com/swiggy-bytes">Swiggy Bytes — Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making Swiggy Buttery Smooth]]></title>
            <link>https://medium.com/swiggy-bytes/making-swiggy-buttery-smooth-5e3a15b931bf?source=rss-ede4f93130a7------2</link>
            <guid isPermaLink="false">https://medium.com/p/5e3a15b931bf</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[swiggy-mobile]]></category>
            <category><![CDATA[performance-improvement]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Agam Mahajan]]></dc:creator>
            <pubDate>Tue, 10 May 2022 09:46:35 GMT</pubDate>
            <atom:updated>2024-04-05T10:13:25.736Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EU_hfUILaWlsoeXHiC6zig.png" /></figure><p>A good mobile developer not only does the day-to-day feature building but also takes care of the performance of the app and tech enhancements.</p><p>At <strong>Swiggy, </strong>providing a seamless experience to our end users is our core focus, where we always push ourselves to make the mobile app smooth as butter and give the best possible experience to the end-users.</p><p>In this article, we will jot down the various tech and app improvements we have made to the Swiggy iOS app.</p><h3>1. Measuring User perceived performance.</h3><p>An improvement of any sort is no good if you don’t have numbers to back it up. Therefore it’s very important, that you always add analytics/instrumentation to see the impact of your changes.</p><p>For our app, we already had page load times. But that is not necessarily significant for the end-user as he/she will perceive page load differently.</p><p><strong>One example is: </strong>When our app is launched, before showing Home Page, we have intermediary screens and logic which also takes some amount of time.<br>So we came up with a Metric called <strong>First Time to be Interactive.<br></strong>How much time will it take for users to interact with our app?<br>This is the time taken from the app icon clicked to our Home Page Rendered.</p><blockquote>In iOS terms, it starts from AppDelgate to Splash Screen to SDKs Initialization to Location Fetch and then Home Page Rendered after API call.</blockquote><p><strong>Another example is: </strong>From the moment user clicks on any Restaurant from anywhere to the time its Menu Page is rendered - <strong>Menu Screen Load Time</strong></p><blockquote>In iOS terms, it starts from didSelectItem to Push View Controller to Menu Page Rendered after API call.</blockquote><p>We then started measuring these kinds of metrics over NewRelic and worked on improving those numbers. After our changes below, we were able to clearly see the reduced load times via graphs.</p><h3><strong>2. </strong>Smart API sequencing</h3><p>Like any other app, we also have our Home Page where we show all our offerings. But this is not the first screen the user sees. First comes Location Screen, where we show the user&#39;s current location. After that comes the Home Screen, where we call a home API to fetch the data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FzxyQWwDAQKXYg78AAq2uQ.png" /><figcaption>Steps before Home Page is rendered</figcaption></figure><p>As of now, we were calling all these APIs synchronously, one after another.<br>Our Home API just needs latitude and longitude to give us the required data.</p><p>Then we thought, why not call our Home API as soon as we get the user&#39;s location, cache the response in the app, and then when the user lands on Home Screen, use that response to render the page.</p><p>This means, that the user doesn&#39;t have to wait on the Home Screen for the API call to complete. Instead, that page will be loaded instantly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OYNTJfkYEeW5pjQ073zyLw.png" /><figcaption>Parallel API Calling</figcaption></figure><p>Side by side comparison of the app before and after this. Won’t tell which is which. It should be visible :P</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*pfMd1w1ilD0axIc2iRiyig.gif" /><figcaption>Before and After Smart API Sequencing</figcaption></figure><p>Talking about the numbers, these changes have helped us <strong>reduce our First Screen Visible time by half (from 6 secs to 3 secs)</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zh4wWTvAlEKCpIMYu8eVRA.png" /><figcaption>Time taken from App Launched to Home Page Rendered</figcaption></figure><h3>3. Prefetching API Response</h3><p>In cities where we have multiple offerings besides food, we have kept a tab bar where our 1st tab is Home Page which is a landing page that shows all our offerings. And our 2nd tab is the Food Page which shows the collections of restaurants in your area.<br>As Food is our MSP, we thought why not prefetch the second tab response beforehand only. Thus when the user switches tabs, he/she would not experience any loading state.<br>This technique helped us <strong>reduce our Food Tab Load Time from</strong> <strong>2 secs to 0.5 sec</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/668/1*_4UKsCQc2lb-kGS5EyI55w.gif" /><figcaption>Left one without prefetching and right one with prefetching response</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FWULMCSJgTeG5p7FjdLQMQ.png" /><figcaption>Time taken from 2nd Tab Clicked to 2nd Page Rendered</figcaption></figure><h3>4. Rendering Smaller Images on Bigger Views as placeholders</h3><p>Swiggy is a content-rich app. For any Restaurant Item, its image appeals a lot to the user. Therefore the quality should be best for that. But a good quality image will be large in size and takes time to download. We faced the same problem on our Menu Detail page where the image takes a lot of time to download as it&#39;s large in size.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/250/1*LC4qz64-OthfoDVm7jy5Rw.png" /></figure><p>To fix this problem, we came up with a unique idea. We already had the same image in a different dimension for the in-line menu item. We thought why not use that image as a placeholder till the time, the bigger image gets downloaded.<br>We expanded the smaller image over the bigger image view, which looked a little blurry but gave a preview of the dish and when the bigger image was downloaded, we safely replace the same.<br>This gives the user a feel of a progressive image without increasing any network usage.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*TFZIPbgzMWgUKCLuHW2kkQ.gif" /></figure><h3>5. Managing Image Scale Factor</h3><p>Different devices have different pixel densities. Therefore they can have different DPR(device pixel ratio). Depending on the device, we can accomplish better rendering by multiplying the number of pixels in each image by a specific scale factor. That&#39;s why we have 2x and 3x images in our Xcassets file.</p><p>For our remote images also, we add the scale factor(image multiplier) to fetch higher resolution images depending upon devices. For eg: If we have an imageView of 50*50 and a device let&#39;s say iPhone Xs, we fetch 3x image size(150*150) from our remote server.</p><p>Recently we revamped our whole UI. On our Menu page, the dish image size got increased. Bigger dimension images started taking more time to download, therefore increasing our page load time.</p><p>What we observed was, that if the images are not that big in a size, for higher density phones, instead of making the dynamic scale factor (3x), we can make it 2x, it won&#39;t have any visual difference, but the size decreases significantly.<br>This has helped us in reducing our page load time significantly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/516/1*KPYQwR2pUWTK-e9sj7Fqiw.png" /><figcaption>The same image with 3x resolution is 19KB and 2x is 9KB</figcaption></figure><p>Note: For our bigger images, we have still kept the dynamic scale factor so that image quality is not compromised.</p><h3>6. Navigation Bar Smoothening</h3><p>Navigation is the most important part of the user experience. Our goal is to help users move swiftly in the app. On many screens, our navigation experience was broken. When the user tried to navigate with the swipe gesture, our navigation bars started breaking.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uMgJb6vehbrele8_Yof-5w.png" /><figcaption>Broken Transitions</figcaption></figure><p>This was happening because we were using a mix of default navbars and custom views. And, hiding/unhiding those navbars was causing the issue.</p><p>Thus, to fix it, we came up with our own navigation system, which can act either as a default navigation bar or as a custom view. Each View Controller has a base class through which the VC can initialize Navbar. It can be initialized by passing title, subtitle, and bar button items making it similar to the default navbar or a custom view can be passed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eF4_6CjcdrAbTDen5QUIOA.png" /><figcaption>Initialize Navbar through Base VC</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Fcxyo2YeFBNjBX63Ug7CSA.png" /><figcaption>Transitions now working smoothly</figcaption></figure><h3>7. App size Reduction</h3><p>In addition to making the app smoother and faster, we should also take care of our app size.</p><p>Since Swiggy as a company is getting into different offerings, our code, libraries, and assets also keep on increasing. It&#39;s very important for us to keep a check on our app size and try to reduce it as much as possible so that a user doesn’t feel that we are taking up too much space on their device.</p><p>We did a couple of exercises to help achieve our goal</p><ol><li>We scanned our app for unused media assets. Removed which were no longer getting used.</li><li>We scanned our app for unused libraries and removed the same.</li><li>For our image assets, we ran them over the <a href="https://tinypng.com/">Tiny PNG</a> tool which optimized our images and reduced the image sizes significantly.</li></ol><h3>What does TinyPNG do?</h3><blockquote>TinyPNG uses smart lossy compression techniques to <strong>reduce the file size</strong> of your WEBP, JPEG and PNG files. By selectively decreasing the number of colors in the image, fewer bytes are required to store the data. The effect is nearly invisible but it makes a very large difference in file size!</blockquote><p>All these exercises help in <strong>reducing app size by ~8MB. </strong><br>This is an ongoing exercise and we will continuously optimize our app size.</p><h3>8. Clear Media Cache</h3><p>Over the period, any app’s cache keeps on increasing. The main contributor to this is Videos and Images. And, increase in cache means an increase in the user’s storage.</p><p>Unlike Android, iOS doesn&#39;t give an option to the user to clear a specific app’s cache. We thought why not give an inbuilt setting within the app for users to clear the media cache (accumulated by caching videos and images).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*pLIc9kI-kuRlSW3xQeHVNw.png" /></figure><p>This option gives power to the user to see the run time app consumption and clear the same.</p><h3>Conclusion</h3><p>Being a consumer-first organization, we at <strong>Swiggy</strong> are not just focused on creating an interactive user interface but are also driven to create a high-quality, enhanced, and buttery smooth user experience. 🧈</p><blockquote>Credits to the entire iOS team of Swiggy for helping to achieve these performance improvements.<br><a href="https://medium.com/u/cb86010f8eb">Mitansh Mehrotra</a>, <a href="https://medium.com/u/4d81372863f6">NIHAR RANJAN</a>, <a href="https://medium.com/u/9e32ea731bff">Shashwat Mithyantha</a>, <a href="https://medium.com/u/828c8792b774">Priyam Dutta</a>, <a href="https://medium.com/u/6fcc2857c082">Ashirvad Jena</a>, <a href="https://medium.com/u/fac662e5a2ea">sreekanth m</a>, <a href="https://medium.com/u/37866fe157b4">Hari Krushna Sahu</a>, <a href="https://medium.com/u/8954ff43cd93">Garima Bothra</a>, <a href="https://medium.com/u/44f8a24a0ac4">Lunasahil</a>, <a href="https://medium.com/u/4bb1b7609dfe">Mayank Jha</a></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5e3a15b931bf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swiggy-bytes/making-swiggy-buttery-smooth-5e3a15b931bf">Making Swiggy Buttery Smooth</a> was originally published in <a href="https://medium.com/swiggy-bytes">Swiggy Bytes — Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Designing the Swiggy app to be truly ‘accessible’ | Episode-3]]></title>
            <link>https://medium.com/swiggy-bytes/designing-the-swiggy-app-to-be-truly-accessible-episode-3-ec7256401c6d?source=rss-ede4f93130a7------2</link>
            <guid isPermaLink="false">https://medium.com/p/ec7256401c6d</guid>
            <category><![CDATA[accessibility]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[swiggy-engineering]]></category>
            <dc:creator><![CDATA[Agam Mahajan]]></dc:creator>
            <pubDate>Sun, 03 Oct 2021 06:45:37 GMT</pubDate>
            <atom:updated>2021-10-03T06:45:37.384Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZTvUMeX5CwbQS-yjSSEKXQ.jpeg" /><figcaption>One app for All</figcaption></figure><p>In our earlier <a href="https://bytes.swiggy.com/designing-the-swiggy-app-to-be-truly-accessible-episode-1-35ef43e5d4e4">blog post</a>, we shared how we went about identifying the accessibility gaps in Swiggy and our design philosophy to address those gaps. In this one, we will share how we made improvements on <strong>iOS</strong> for the food ordering flow.</p><h3>What did we do?</h3><p>For our iOS app, we have focussed on making the app compatible with two kinds of disabilities</p><ol><li><strong>Vision</strong>: For visually challenged users</li><li><strong>Physical and Motor</strong>: For physically challenged users</li></ol><h3>How we did it?</h3><p>Before we get started on the implementation, there are few accessible properties that we have used in iOS</p><ol><li><strong>Label</strong>: This property is used to assign the name to our element.</li><li><strong>Traits</strong>: These describe the element’s state, behavior, or usage. A button trait might be <strong>is selected</strong>.</li><li><strong>Hint</strong>: Describes the action an element completes. eg: <strong>Displays the menu restaurant</strong>.</li><li><strong>Frame</strong>: The frame of the element within the screen, in the format of a CGRect.</li><li><strong>Value</strong>: The value of an element. For example, with a progress bar or a slider, the current value might read <strong>5 out of 100</strong>.</li><li><strong>Accessible Element</strong>: View or component for which accessibility is enabled.<br>You can set accessibility for a Label/Button or you can make a whole view as one accessible element.</li><li><strong>isAccessibilityElement</strong>: This boolean flag is used to enable/disable the accessibility property of any element.<br>If it&#39;s set to off, OS will not read it.</li></ol><p>If you are not familiar with the basic implementation of Accessibility, can go through a starter project on the same. <a href="https://www.raywenderlich.com/6827616-ios-accessibility-getting-started"><strong><em>Link</em></strong></a></p><h3><strong>Vision</strong></h3><p>For people whose vision is impaired, Apple has provided a feature called <strong>VoiceOver</strong>.<br>Users can interact and navigate with the app using different hand gestures.</p><p>VoiceOver can be enabled in the Accessibility section of Settings.<br>Once it&#39;s enabled, OS will point to the first accessible element in the screen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/281/1*-Pz-Y6FKpBFAH-sJMxtKzw.png" /></figure><p>Basic hand gestures used for Voice Over</p><ol><li><strong>Swipe right</strong>: It jumps to the next accessible element.</li><li><strong>Swipe left</strong>: It jumps to the previously accessible element.</li><li><strong>One finger double tap</strong>: Clicks the selected accessible element.</li></ol><p>For more commands, you can check the VoiceOver settings in the app.</p><p>Following are the different handlings we did in our app to smooth the interaction of Accessible User.</p><h3><strong>Grouping the Views</strong></h3><p>As many accessibility services function in a linear manner and shift focus from one element to the next. If our UI component is not grouped according to functionality, users may have to perform multiple focus shifts to reach the next item/action item.</p><p>This problem can be solved by grouping UI components together which logically represent one unit.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CW3HxeVI5SkTksuD.png" /><figcaption>Image 1. Restaurant entities are not grouped.</figcaption></figure><p>As you can see in the above image, restaurant entities are not grouped together so users can’t hear all the information at once. Users need to change focus every time they need to hear another information.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Vd_zuyE7srHeEE7m.png" /><figcaption>Image 2. Restaurant entities are grouped.</figcaption></figure><p>In the above image, you see all restaurant entities are grouped together so the user will hear all the focused information at once without shifting focus multiple times.</p><p>This can be achieved very easily by making the parent view’s <strong>isAccessibilityElement </strong>property true. OS will treat that view as one property.<br>Also assigning the Restaurant Name and its info to the Label property of that view</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/17e55fd9ba4fbbdf8b0a9ddb8888a178/href">https://medium.com/media/17e55fd9ba4fbbdf8b0a9ddb8888a178/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_2EyKbLeNVzCs_o8fIkmBg.png" /></figure><p>Grouping of the components has been used extensively in our app to make the experience better.</p><h3><strong>Accessibility Support for Images/Banners</strong></h3><p>In the Swiggy app, we have a lot of components that only contain images/banners.<br>So assigning a meaningful Name to each image view was challenging.</p><p>We came up with a solution where we added an <strong>Alt text </strong>with the image response itself from the backend.<br>Then we used that alt text and assigned it to the Accessibility Label.<br>This Alt text contains a meaningful description of the image/banner.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9ee3bec94e007d95eda2ea917dbe28d0/href">https://medium.com/media/9ee3bec94e007d95eda2ea917dbe28d0/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UBYlUm-rj1u91PY9HwdV2g.png" /></figure><h3>Announcements</h3><p>Whenever something is processing or an asynchronous request is completed, we have to inform the same to the user.<br>To achieve this we used announcement notifications to let know the user what is happening in the app.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9bfdf06a5274f79161066c554a11e0ca/href">https://medium.com/media/9bfdf06a5274f79161066c554a11e0ca/href</a></iframe><p>We used these announcement notifications for various use cases<br>- App launched with which location<br>- Location changed by the user<br>- When a screen is loaded (after a successful API call)<br>- and many more…</p><h3><strong>Custom Actions Handling</strong></h3><p>If we want to add multiple actions for a particular view component we can do this by using Custom Actions.</p><p>For the Swiggy app, we added multiple actions to each food item on the Menu/Cart page. These actions are <br><strong>- Add item<br>- Remove item<br>- Go to cart</strong></p><p>Note: We added go “Go to cart” action to each item so that the user can easily navigate to the cart as soon as he/she has added the desired item.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/72f146f2e9a5531e392a29a28ea8787f/href">https://medium.com/media/72f146f2e9a5531e392a29a28ea8787f/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TUoRAf8hBlMG_3-ATnI8Qw.png" /></figure><p><strong>Modifying Menu Item Cell<br></strong>For the accessible users, we changed the layout of the item cell, so that users can easily navigate to the cart.<br>When a user adds a quantity, we added a cart button there itself, which acts as a shortcut to go to Cart Page.</p><p>For this, we simply check if it&#39;s a voice-over session, we change the layout.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bc7754681561bca63e4439b28ff9805f/href">https://medium.com/media/bc7754681561bca63e4439b28ff9805f/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/277/1*h_b-sH9qC4tVJnbIgFN36g.gif" /></figure><p><strong>Implementation Video</strong>:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fz0a3qnt3slw%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dz0a3qnt3slw&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fz0a3qnt3slw%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/2ce879fba867029e5dca00f8250955df/href">https://medium.com/media/2ce879fba867029e5dca00f8250955df/href</a></iframe><h3><strong>Physical and Motor</strong></h3><p>For people who can’t use their hands to operate phones, Apple has provided a feature called <strong>Voice Control</strong>.<br>Users can interact and navigate with the app using his/her voice and call different gestures like tap, scroll, swipe</p><p><strong>Voice Control</strong> can be enabled in the Accessibility section of Settings</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/281/1*fsAi2tHG3TQ_Kok-ZYZm3A.png" /></figure><p>Users can use this Voice Control feature mainly by two types of settings.<br>This can be changed inside <strong>Overlay Section</strong></p><ol><li><strong>Item Numbers</strong>: Here OS will determine the accessible elements in the screen and assign numbers to each element.<br>The user will say <br>- “Tap 1”<br>- “Tap 6”<br>Then the particular element will be clicked.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/281/1*CccedVgTMWfUs9E7kNwG6g.png" /></figure><p><strong>2. Item Names</strong>: Here OS will determine the accessible elements in the screen and assign names to each element. <br>The name will be what we set through code in the <strong>Accessibility Label</strong> property<br>The user will say <br>- “Tap Burger King”<br>- “Tap McDonalds”<br>Then the particular element will be clicked.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/281/1*pIBzAbPXW9-sp0O5EDAbcQ.png" /></figure><p>Other commands which users can use are<br>- “Scroll down” / “Scroll up”<br>- “Go Back”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/282/1*AcqBlu87uHPk99xrtMAvww.png" /></figure><p>Most of the tasks are achievable using these commands<br>For more commands and customization, users can add the same in the Voice Control settings.</p><p><strong>Implementation Video:</strong></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FI5Cs-qJ7q5I&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DI5Cs-qJ7q5I&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/f59bb030f4206c4ddc400b1c31882642/href">https://medium.com/media/f59bb030f4206c4ddc400b1c31882642/href</a></iframe><h3>Measure Impact</h3><p>For every feature implemented, we must add some kind of analytics to measure the impact of that feature.<br>After these features were rolled out, we saw an increased number of orders completed by Accessible users.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vi8lwYLSJJA-I5He9PeHZg.png" /></figure><h3>Where to go from here?</h3><ul><li>Now after making our food flow Accessible, we will be focusing on other Swiggy offerings also like Instamart/Genie, etc.</li><li>We are also getting in touch with users and getting feedback on our app and doing changes accordingly so they can get the best possible experience.</li><li>For any new features which we add, we will be supporting accessibility then and there.</li></ul><blockquote>Acknowledging <a href="https://medium.com/u/33574473afde">Sanket Shekhar</a> and <a href="https://medium.com/u/fac662e5a2ea">sreekanth m</a> , for helping in this implementation.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ec7256401c6d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swiggy-bytes/designing-the-swiggy-app-to-be-truly-accessible-episode-3-ec7256401c6d">Designing the Swiggy app to be truly ‘accessible’ | Episode-3</a> was originally published in <a href="https://medium.com/swiggy-bytes">Swiggy Bytes — Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Video Stories and Caching Mechanism(iOS)]]></title>
            <link>https://medium.com/swiggy-bytes/video-stories-and-caching-mechanism-ios-61fc63cc04f8?source=rss-ede4f93130a7------2</link>
            <guid isPermaLink="false">https://medium.com/p/61fc63cc04f8</guid>
            <category><![CDATA[swiggy-engineering]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swiggy-mobile]]></category>
            <category><![CDATA[videos]]></category>
            <dc:creator><![CDATA[Agam Mahajan]]></dc:creator>
            <pubDate>Fri, 11 Sep 2020 13:04:17 GMT</pubDate>
            <atom:updated>2020-09-23T16:01:43.793Z</atom:updated>
            <content:encoded><![CDATA[<h3>Video Stories and Caching (iOS)</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*sdTK6wu5SlaVaJYCfJXwcw.jpeg" /></figure><p>The article will teach you how you can show multiple videos in one view as we see in Instagram Stories.<br>We’ll also learn how to cache the videos in the user’s device to help save that user’s data and network calls and smooth out their experience.<br><strong>NOTE</strong>: This implementation is for iOS, but the same logic can be applied in other codebases as well.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*WXsnzjSBnT5cthK4iyB-_g.gif" /></figure><p>In general, whenever we want to play a video, we get the video URLs and simply present <strong>AVPlayerViewController</strong> with that URL.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/db87b13245bc76aa985443741f98e421/href">https://medium.com/media/db87b13245bc76aa985443741f98e421/href</a></iframe><p>Pretty straightforward right!</p><p>But the drawback of this implementation is you <strong>can’t do customization</strong>, which, if you are working in a good product company, will be every day ask. :D</p><p>One can say, we can alternatively use <strong>AVPlayerLayer</strong> which will do a similar job but the view and other elements we can customize.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/15ae708bf4e742839c33f7b88dfe7324/href">https://medium.com/media/15ae708bf4e742839c33f7b88dfe7324/href</a></iframe><p>But if you say, you want multiple videos to come similar to <strong>Instagram stories</strong>, then we surely have to deep dive a bit.</p><p>Now, Let me tell my use case.</p><p>In Swiggy, we want to show multiple videos, where each video should be shown ‘x’ number of times. <br>On top of it, it should have a Instagram-like stories feature.<br>- Video-2 should seamlessly autoplay after video-1 and so on<br>- Jump to corresponding videos whenever the user taps left or right.</p><p>If caching is the question you have in your mind, I’ll get to that in a bit.</p><p>First thing, how to add multiple videos in one view.<br>What we can do is create one <strong>AVPlayerLayer</strong> and assign the first video to it. When the first video gets completed, assign the next video to the same <strong>AVPlayerLayer</strong> .</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/89f469250d072cfbdd74f998bcf3520d/href">https://medium.com/media/89f469250d072cfbdd74f998bcf3520d/href</a></iframe><p>For jumping to prev or next video:<br>- Add tap gesture on the view<br>- If the touch location ‘x’ is less than half of the screen, then assign prev video, else assign the next video</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/decea47c0c0f81abd6e239586811f845/href">https://medium.com/media/decea47c0c0f81abd6e239586811f845/href</a></iframe><p>There we go. We got our own Insta-like Stories Video feature.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F13ZwNq4FnbM%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D13ZwNq4FnbM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F13ZwNq4FnbM%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/3fef6610b213c803096ce1530795e64d/href">https://medium.com/media/3fef6610b213c803096ce1530795e64d/href</a></iframe><p>But our task is not done yet!!</p><p><strong>Now Back to Caching<br></strong>We don&#39;t want that every time user navigates from one video to another, it again starts to download video from start.</p><p>Also, if the video comes again in the next session, we should not again do a server call. If we can cache the video, then the user’s internet will be saved, and also load on the server will be reduced.</p><p>Also, UX will improve as the user doesn’t have to wait longer to load the video.</p><p><strong>As a good developer, reducing user’s internet usage should be our priority.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/1*uKPCdKkNJy4ggKNnToaGSw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*c2JX7ENalmxjtJfs_MMdQQ.jpeg" /><figcaption>Less Data Usage, Happy Customer</figcaption></figure><p>The first thing we can use to load videos is <strong>loadValuesAsynchronously</strong>.</p><p>According to Apple documentation, <strong>loadValuesAsynchronously:</strong></p><blockquote>Tells the asset to load the values of all of the specified keys (property names) that are not already loaded.</blockquote><p>The advantage of using it is, it saves the video till is rendered. So it will not download the video from the start whenever the user navigates to a previous video. It will only download the part which was not rendered earlier.</p><p><strong>Example</strong>: Video_1 is of 15 secs and the user saw 10 secs of that video and then jump to Video_2. Now if the user comes back to Video_1 again by tapping the left side, <strong>loadValuesAsynchronously </strong>will have that 10 secs video saved and will only download the rest of the 5 secs video.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ce776becff4bcc2ea00662339cb6c500/href">https://medium.com/media/ce776becff4bcc2ea00662339cb6c500/href</a></iframe><p>More details on <strong>loadValuesAsynchronously </strong>can be read on this <a href="https://developer.apple.com/documentation/avfoundation/avasynchronouskeyvalueloading/1387321-loadvaluesasynchronously">link</a>.</p><p>The Caveat of this is it persists video data only for that session only. If the user kills and comes back to the app, then again video has to be downloaded.</p><p>Now comes the <strong>Video Caching</strong>!</p><p>What we can do here is when the video is rendered completely, we can export the video and save it to the user’s device. When the video comes again in the next session, we can pick the video from the device and simply load it.</p><p><strong>AVAssetExportSession<br></strong>According to Apple documentation:</p><blockquote>An object that transcodes the contents of an asset source object to create an output of the form described by a specified export preset.</blockquote><p><strong>What it means is, AVAssetExportSession acts as an exporter, through which can save the file to the user’s device. We have to give the output URL and output file type.</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3c7afbd85c8a229140e2fd9f307dd856/href">https://medium.com/media/3c7afbd85c8a229140e2fd9f307dd856/href</a></iframe><p>More details on <strong>AVAssetExportSession </strong>can be read on this <a href="https://developer.apple.com/documentation/avfoundation/avassetexportsession">link</a>.</p><p>Now the only thing left is to fetch from the cache and load the video.<br>Before loading, check if the video is present in the cache, fetch that local URL and give it to <strong>loadValuesAsynchronously.</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ace79ce1e56c62042f3a533be4b0e40e/href">https://medium.com/media/ace79ce1e56c62042f3a533be4b0e40e/href</a></iframe><p><strong>Caching will help reduce a lot of user data as well as server load. The impact will be in TBs</strong></p><p>What other use cases we can handle while doing the caching. These can be optional based on your use case.</p><p><strong>1. Ensure Optimum Storage</strong><br>Before saving the video in the device, check whether enough storage is present in the device or not.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f686a09503fe5fe6b5053873999387d9/href">https://medium.com/media/f686a09503fe5fe6b5053873999387d9/href</a></iframe><p><strong>2. Remove Deprecated Videos</strong><br>Have a timestamp to each video, so that you can clean videos from device memory after x days.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ab6375d7a5b6a5f5879be3a92af1a7a6/href">https://medium.com/media/ab6375d7a5b6a5f5879be3a92af1a7a6/href</a></iframe><p><strong>3. A limited number of Videos</strong><br>Have only limited videos saved in the file at a time. Let&#39;s say 10. When the 11th video comes, delete the least used video and replace it with the new one. This will also help to not consume too much of the user’s device memory.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f64d3a9c3980d436acb46084c95050e6/href">https://medium.com/media/f64d3a9c3980d436acb46084c95050e6/href</a></iframe><p><strong>4. Measure Impact</strong><br>Don’t forget to add logs, so that you can measure the impact of your feature.<br>I have used a custom New Relic Log Event.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/766ccdf6673935d1391ac10dfcccd2a1/href">https://medium.com/media/766ccdf6673935d1391ac10dfcccd2a1/href</a></iframe><p>To convert file size to a readable format, I&#39;m fetching file size and converting it to Mbs.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/79fe78ae45302e2cb64b5e3c73dfa898/href">https://medium.com/media/79fe78ae45302e2cb64b5e3c73dfa898/href</a></iframe><p>This is how you can measure your impact.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*raqNLU8fUa0XsYTn61xUFQ.png" /></figure><p><strong>Total data saved = no of request * video_size = 2.4MB*20.3K ~= 49GB</strong></p><p>This is just two weeks of data. You do the math for the whole year. 😁<br>And this will keep on increasing exponentially over time.</p><p>That’s it!!<br>You have your own caching mechanism.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/498/1*9z30jkXrUZw4D2TyINfEYA.gif" /></figure><h3>Wrapping up</h3><p>To conclude here, we saw how easily we can integrate multiple videos in one view itself, giving an Instagram-like story feature.<br>Also why and how the caching mechanism plays an important role here. And how it will help the user to save a lot of data besides having a smooth user experience.</p><p>Do let me know if I missed something. Or if you can think of any more use cases.<br>Thanks for your time. :)</p><blockquote>Acknowledging <a href="https://medium.com/u/4d81372863f6">NIHAR RANJAN</a>, for helping in this implementation.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=61fc63cc04f8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swiggy-bytes/video-stories-and-caching-mechanism-ios-61fc63cc04f8">Video Stories and Caching Mechanism(iOS)</a> was originally published in <a href="https://medium.com/swiggy-bytes">Swiggy Bytes — Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CA Animation, which took away my fear of Animations]]></title>
            <link>https://medium.com/swiggy-bytes/ca-animation-which-took-away-my-fear-of-animations-7fded1a2a681?source=rss-ede4f93130a7------2</link>
            <guid isPermaLink="false">https://medium.com/p/7fded1a2a681</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[swiggy-mobile]]></category>
            <category><![CDATA[swiggy-engineering]]></category>
            <category><![CDATA[caanimation]]></category>
            <dc:creator><![CDATA[Agam Mahajan]]></dc:creator>
            <pubDate>Thu, 19 Mar 2020 04:53:20 GMT</pubDate>
            <atom:updated>2020-03-19T04:53:20.609Z</atom:updated>
            <content:encoded><![CDATA[<p>This article focuses on the usage of CA Animations in iOS to make smooth animations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*An6Zl1vA6S6nYrFXZvcOXw.gif" /></figure><p>During my initial days with iOS, one thing I used to fear was whenever a designer comes up and says he/she wants an animation in the app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*BWbcgO2n4v8FL4FhuGNelw.gif" /><figcaption>Shiiiiiiit</figcaption></figure><p>In my mind, I used to think, it&#39;s very easy to come up with the design of animation but to implement is a very difficult task.<br>I used to take the help of Google/StackOverflow/Peers for the implementation. <br>I had a phobia using animations and have always tried to avoid it, but this soon changed.</p><p>At one instance, I had to animate a sequence of images in a view.<br>So what would have been my first step? Obviously, StackOverflow!<br>The first link got the code.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9a9a5532c96255f64ac0a0b055b6e05d/href">https://medium.com/media/9a9a5532c96255f64ac0a0b055b6e05d/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*B7oreRX0tGZEDMUJKVa6xg.gif" /></figure><p>Easy peasy right? Well, if it were that simple, I wouldn’t be writing this article :P</p><p>This is the actual requirement.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*WJVqVU2q2F9MJmqznWpbvg.gif" /><figcaption>End Goal</figcaption></figure><p>As it may be clear by now, I was nowhere close to it. In fact, I was stuck. ‘How would I be able to do so many customizations in animation and sync all of them?’</p><p>Then my friend told me to try CA Animation(Core Animation). I read about the same and tried on a sample project. To my amazement, it was so easy and powerful to use.</p><p>Core Animation provides high frame rates and smooth animations without burdening the CPU and slowing down your app. Most of the work required to draw each frame of an animation is done for you. You configure animation parameters such as the start and endpoints, and Core Animation does the rest, handing off most of the work to dedicated graphics hardware, to accelerate rendering</p><p>In a few hours, I was able to do a basic implementation.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2f8ac421ea1370f5ecb3d7771b62f8ad/href">https://medium.com/media/2f8ac421ea1370f5ecb3d7771b62f8ad/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*rgCswWRjymj8FTUoq-3cQw.gif" /><figcaption>CA Basic Animation</figcaption></figure><p>For this implementation, I used <strong>CABasicAnimation</strong>.</p><p><strong>CABasicAnimation</strong> class animates a layer property between two values, a starting, and an ending value. To move a layer from one point to another in its containing window. For example, we can create a basic animation using the keypath position. We give the animation a start value and an ending value and add the animation to the layer. The animation begins immediately in the next run loop.<br>You can use CA Basic Animation for animating many things like background color, opacity, position, scale.<br>More details: <a href="https://developer.apple.com/documentation/quartzcore/cabasicanimation">https://developer.apple.com/documentation/quartzcore/cabasicanimation</a></p><p><strong>Now, back to our problem</strong>. <br>How did I go about implementing this? I took two image views and added two separate images to them. Then, I kept on animating them one after the other using CA animation.<br>Full Code implementation: <a href="https://gist.github.com/agammahajan1/e9b550f0275418459982246d1ee905d5">https://gist.github.com/agammahajan1/e9b550f0275418459982246d1ee905d5</a></p><p>If you carefully see my last implementation gif, you will notice that something off. Before the first image goes out of the view, for example, the gift box gets immediately changed to headphones and then it goes up.</p><p>Why it is happening?</p><blockquote>Because as soon we are adding the animation to the image view, we are adding the next image to that view. (line number 5 and 6)</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/265e6561ad1e561533e27a090a146ef3/href">https://medium.com/media/265e6561ad1e561533e27a090a146ef3/href</a></iframe><p>This is the issue of how to sync both image animations. But there always a solution with CA Animation.</p><p><strong>CA Transactions<br></strong>CATransaction is an often overlooked class by most developers. The job of CATransaction is to group multiple animation-related actions together. It ensures that the desired animation changes are committed to Core Animation at the same time.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4588a4d2de6a90a5965f2dfb2d414a0f/href">https://medium.com/media/4588a4d2de6a90a5965f2dfb2d414a0f/href</a></iframe><p>You start by writing CATransaction.begin(). Then write all your animations which you want to do in sync. Then call CATransaction.commit() which will start the animation in the block.<br>Also, you can give a completion block to your animations.</p><p>Let&#39;s see how our animation looks now.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/380/1*quiMVcW7CNzoSSFH-IvMeA.gif" /></figure><p>One last thing was to add the Spring effect in the animation. Thankfully, CA Animation had a solution for it too.</p><p><strong>CA Spring Animation<br></strong>You would typically use a spring animation to animate a layer’s position so that it appears to be pulled towards a target by a spring. The further the layer is from the target, the greater the acceleration towards it is.</p><p>It allows control over physically-based attributes such as the spring&#39;s damping and stiffness.<br>Let&#39;s implement it then.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f58dd992daf661a6d655d9c7ecd6460a/href">https://medium.com/media/f58dd992daf661a6d655d9c7ecd6460a/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Hd6u1nwLDgIgbthJOqKxUg.gif" /><figcaption>Voila</figcaption></figure><p>My work is done here.</p><p>To <strong>Conclude</strong>, here are some advantages of using CA Animations<br>- Easy to use and implement<br>- A lot of customizations available<br>- Can sync multiple animations<br>- Almost 0 CPU usage</p><p>These are just a few of the advantages. The possibilities are endless.</p><p>Now, whenever requirements come for animation, I feel confident to implement the same. <br>And I hope you also feel the same way after reading this.<br>Feel free to give any suggestions or feedback.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7fded1a2a681" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swiggy-bytes/ca-animation-which-took-away-my-fear-of-animations-7fded1a2a681">CA Animation, which took away my fear of Animations</a> was originally published in <a href="https://medium.com/swiggy-bytes">Swiggy Bytes — Tech Blog</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 make an iOS on-demand build system with Jenkins  and Fastlane]]></title>
            <link>https://medium.com/free-code-camp/how-to-make-an-ios-on-demand-build-system-with-jenkins-and-fastlane-8eb1e02c73d1?source=rss-ede4f93130a7------2</link>
            <guid isPermaLink="false">https://medium.com/p/8eb1e02c73d1</guid>
            <category><![CDATA[continuous-delivery]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[automation]]></category>
            <dc:creator><![CDATA[Agam Mahajan]]></dc:creator>
            <pubDate>Tue, 23 Oct 2018 01:11:09 GMT</pubDate>
            <atom:updated>2018-10-23T01:11:09.889Z</atom:updated>
            <content:encoded><![CDATA[<h3>How to make an iOS on-demand build system with Jenkins and Fastlane</h3><p>This article is about creating iOS builds through Jenkins BOT, remotely, without the need of a developer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/690/1*RmcSmwPhUn8ljLiiwYxK0A.png" /></figure><p>Before starting, I want to say that this is my first article. So feel free to leave a comment if something can be improved :)</p><h4><strong>Why is this a good idea?</strong></h4><p>When a developer makes a feature, they QA test it before pushing it to production. So a build has to be shared with the QA team with some test configurations.</p><p>Xcode (the IDE) takes a significant amount of time to compile and generate this build. This means that any person that needs the build would have to install the IDE, clone the repository, create a signing identity and certificate and then create the build themselves. Or depend on the developer to create one for them.</p><p>During the build creation process, the IDE is unusable. This severely impacts the productivity of the developer. In my company, the average build time of an .ipa is around 20 mins. On average, a developer makes 2–3 builds daily.<br>This means 5 working hours a week get wasted.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/620/1*GFEYrijn6zJapmjaN2V4dA.jpeg" /><figcaption>How much more time will it take to build?</figcaption></figure><p>But what if there was an automated system which could generate the builds on its own? This would free the developers from this responsibility. It would also make it possible for anyone to get a build easily.</p><p>Jenkins is one of the solutions to our problem.</p><p>Making builds easily available to testers and developers ensures that people are able to test features faster and ship to production more easily. This improves the productivity of development teams. It also improves the quality of products pushed to production.</p><h3><strong>Let’s get started now.</strong></h3><h4><strong>Prerequisites</strong></h4><p>You will require:</p><ul><li>macOS Machine (it is better to run it on Mac products)</li><li>10 GB of drive space (for Jenkins)</li><li>Java 8 installed (either a JRE or Java Development Kit (JDK) is fine)<br><a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html">http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html</a></li></ul><p><strong>Additional Plugins to be installed</strong></p><ul><li>homebrew</li><li>wget</li><li>RVM Plugin<br><a href="http://usabilityetc.com/articles/ruby-on-mac-os-x-with-rvm/">Installation guide</a><br><a href="https://rvm.io/rvm/security">https://rvm.io/rvm/security</a></li></ul><p>Make one Branch with a file in it with the name Jenkinsfile with sample code:<br><em>node {<br> sh ‘echo HelloWorld’<br>}</em><br>Let&#39;s name it <strong>jenkins-integration</strong>. Will come back to this later.</p><ul><li>Install Xcode on your machine from the App Store</li><li>Install Fastlane on your machine. Jenkins will internally use fastlane commands to generate builds.</li></ul><p>Now let’s go through it step by step.</p><h3><strong>Step 1. Install Jenkins on your machine</strong></h3><p>You can install on a MacBook or mac-mini. Mac-mini is preferred as it can be kept alive.</p><p>Download Jenkins -&gt; <a href="https://jenkins.io/">https://jenkins.io/</a></p><p>Run <strong>java -jar jenkins.war --httpPort=8080</strong> in the command line. If you’re getting an error in the terminal, try a different port (for example, 9090) as sometimes some ports are not available.</p><p>Browse to <a href="http://localhost:8080/">http://localhost:8080</a> and follow the instructions to complete the installation.</p><p>Then add admin credentials and don’t forget them (as did I :P). Later you can go to <strong>Jenkins &gt; Manage Jenkins &gt; Manager Users </strong>and do your changes if needed.</p><h3>Step 2. Creating Your first Pipeline</h3><p>Create a new job and choose <strong>Pipeline Project</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cN7MqM8LaClcPg29kVGq_Q.png" /></figure><p>To check out your project, under the section <strong>Pipeline, </strong>in <strong>Definition, </strong>choose <strong>Pipeline Script from SCM</strong> and in SCM choose <strong>Git</strong></p><p>Then add your repo URL and add the credentials if its a private repo. In branches to build , add */<strong>jenkins-integration,<em> </em></strong>the branch which we created earlier.</p><p>Make sure Script Path is <strong>Jenkinsfile</strong> which we have created in our new branch. All the scripts will be written in this Jenkinsfile.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*l6wpHeIHZZ5ZuoTjcdJoLA.png" /></figure><p>Click on Save and Jenkins will automatically scan your repo with the mentioned branch and will run the Jenkinsfile script.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v7QhFuQlGH9YhjEruS52nw.png" /></figure><p>Now we are ready to configure our Jenkinsfile to create builds</p><h3>Step 3. Add parameters to the Job</h3><p>User input is required for</p><ul><li>branch</li><li>environment (test or prod)</li></ul><p>For that we need to configure our project to take input parameters for a job.</p><p>Go to the <strong>Configure</strong> section and check <strong>This project is parameterised<em>.</em></strong><em><br></em>Then select add parameter and add the same accordingly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EfmwPbDPa-YwWAZ-rEU2cw.png" /></figure><p>When you click on save, you will see a new section on left side -&gt; <strong>Build with Parameters</strong>. This will be the user interface to make builds.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*msne-k6C4ksZdj8NpbGdrA.png" /></figure><p>These params will be used in our Jenkins script.</p><h3>Step 3. Configure Jenkins Script</h3><p>Will create multiple steps in our Jenkinsfile, each having one responsibility, and it will create a nice UI when it is built.</p><p>Go to your Jenkinsfile and replace the script with the following:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9cce8ca3248cf58e0e01e277f6ba58b5/href">https://medium.com/media/9cce8ca3248cf58e0e01e277f6ba58b5/href</a></iframe><p>First, check out the branch through the parameter which we added earlier. Add your repo and GitHub token.</p><p>Now the GitHub token should not be visible to others. To do this, go to <strong>Manage Jenkins</strong>-&gt; <strong>Configure System</strong> -&gt;<strong>Global properties </strong>and add <strong>githubToken </strong>as an environment variable.</p><p>Then invoke the script to change the environment.</p><p>Next, invoke fastlane to clean (remove derived data, clean, delete .dsym files etc).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/de3e4a42f2fb7c6e48561949395ec7d8/href">https://medium.com/media/de3e4a42f2fb7c6e48561949395ec7d8/href</a></iframe><p>If code signing is required, do that next using <strong>ad-hoc</strong>. You can use <strong>development</strong> or <strong>app store</strong> based on your needs.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d371f6ca4361e2507ccd5e3d4cafb50e/href">https://medium.com/media/d371f6ca4361e2507ccd5e3d4cafb50e/href</a></iframe><p>Next, create builds using the <strong>gym</strong> command in fastlane.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2108ac95d1b67f89b2cae56da691c5af/href">https://medium.com/media/2108ac95d1b67f89b2cae56da691c5af/href</a></iframe><h3>Step 4. Run the Job</h3><p>Now our script is ready. Go to Jenkins and open <strong>Build with Parameters.</strong></p><p>It will start to run the script and will create a nice UI with multiple steps as mentioned in the Jenkinsfile.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*atL19HWAh9PkfnyxjfcsMg.png" /></figure><p>When the job is completed, go to the project <strong>Users/agammahajan/.jenkins/workspace/iOS_Build_Systems<br></strong>and you will see that the .ipa has been created. Voilà!</p><p>Now you can share this build with others. You can use the Slack plugin to upload the builds to Slack if you want.</p><h4>Wrapping up</h4><p>So to conclude here, we can see how easy it is to setup an automated bot which enables any person to trigger builds in just 2 steps: <strong>Give Branch-&gt;Test Environment-&gt; Done.</strong></p><p>This has helped me and my fellow developers improve productivity and ship faster. It has also helped the QA team, so that they don’t have to depend on developers every time they need to test something. I hope it benefits you and your company also.</p><p>From here, the <strong>possibilities</strong> are endless.</p><ol><li>You can make scheduled jobs to generate nightly builds.</li><li>Upload builds directly to the App Store.</li><li>Cache the builds, so builds with the same configuration are not generated again.</li><li>Distributing the IPA in house for OTA (Over the air) installation.</li><li>Make a CI-CD pipeline to run automated tests on every commit and make them production ready.</li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8eb1e02c73d1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/free-code-camp/how-to-make-an-ios-on-demand-build-system-with-jenkins-and-fastlane-8eb1e02c73d1">How to make an iOS on-demand build system with Jenkins  and Fastlane</a> was originally published in <a href="https://medium.com/free-code-camp">We’ve moved to freeCodeCamp.org/news</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>