<?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 Sneh Pandya on Medium]]></title>
        <description><![CDATA[Stories by Sneh Pandya on Medium]]></description>
        <link>https://medium.com/@snehpandya18?source=rss-7dc08545ed6d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*02vPPBmn5v8vCZ48NFYt0A.png</url>
            <title>Stories by Sneh Pandya on Medium</title>
            <link>https://medium.com/@snehpandya18?source=rss-7dc08545ed6d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 23:14:54 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@snehpandya18/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[Introduction to Infrastructure as Code: A Brief Guide to the Future of DevOps | Sneh Pandya | Riya…]]></title>
            <link>https://snehpandya18.medium.com/book-author-sneh-pandya-launch-infrastructure-as-code-future-of-devops-riya-thakurta-60cc88c67f78?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/60cc88c67f78</guid>
            <category><![CDATA[books]]></category>
            <category><![CDATA[business]]></category>
            <category><![CDATA[authors]]></category>
            <category><![CDATA[publishing]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Fri, 24 Mar 2023 03:41:33 GMT</pubDate>
            <atom:updated>2023-08-16T06:56:46.153Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introduction to Infrastructure as Code: A Brief Guide to the Future of DevOps | Sneh Pandya | Riya Guha Thakurta | Apress Publication | Book Launch</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/0*_cdQYrT-MAd-O44z" /><figcaption>Introduction to Infrastructure as Code | Sneh Pandya | Riya Guha Thakurta | Apress Publication | Book Launch</figcaption></figure><blockquote><em>For parents, who gave everything, and always seem to find a way to give more.</em></blockquote><p>Proudly announcing the publication of this collaborative effort!</p><p><a href="https://www.linkedin.com/in/riyagt/">Riya Guha Thakurta</a> and I have co-authored the book <strong>Introduction to Infrastructure as Code: A Brief Guide to the Future of DevOps </strong>with <a href="https://www.linkedin.com/company/apress/">Apress</a>.</p><p><a href="https://link.springer.com/book/10.1007/978-1-4842-8689-0">Get the book ↗</a> | <a href="https://devopsbook.co/">devopsbook.co ↗</a></p><p><a href="https://www.amazon.com/Introduction-Infrastructure-Code-Future-DevOps/dp/148428688X/">Amazon ↗</a> <a href="https://www.amazon.com/Introduction-Infrastructure-Code-Future-DevOps-ebook/dp/B0BMQDT4JK/">Amazon Kindle ↗</a> <a href="https://www.oreilly.com/library/view/introduction-to-infrastructure/9781484286890/">O’Reilly ↗</a></p><p><a href="https://www.barnesandnoble.com/w/introduction-to-infrastructure-as-code-sneh-pandya/1141877861?ean=9781484286883">Barnes &amp; Noble ↗</a> <a href="https://books.telegraph.co.uk/Product/Sneh-Pandya/Introduction-to-Infrastructure-as-Code--A-Brief-Guide-to-/27331880">Telegraph ↗</a> <a href="https://www.google.co.in/books/edition/Introduction_to_Infrastructure_as_Code/ObdIzwEACAAJ?hl=en&amp;kptab=overview">Google Books ↗</a></p><p>In today’s rapidly transforming world, Infrastructure-as-Code (IaC) has emerged as an effective approach to maintain, scale, and deploy software systems.</p><p>Riya and I co-authored this book to share anecdotes from our constantly evolving industry experiences in varied capacities that would help the enthusiasts in field of Cloud Infrastructure and DevOps.</p><p>This book is aimed at the beginners interested in building a career in DevOps as well as professionals looking to gain expertise and advance their career with greater knowledge of IaC, including Technical Product Managers, and Architects.</p><p>The perspectives presented here focus on key themes of advancements in the field of DevOps, methodologies and best practices, issues in deploying and managing applications at scale; as well as continuous improvement and benchmarking of production systems.</p><p>This book is a combination of fundamental knowledge and practical experience. This book highlights the significance of the DevOps culture and how to implement Infrastructure-as-Code (IaC) within your organization. The book conceptualizes the adoption and expansion goals that DevOps and Infrastructure-as-Code (IaC) have for various industries.</p><p>The book provides hands-on examples utilizing IaC platforms, open source tools, and essential considerations such as security, scalability, and deployments. Each chapter focuses on one vertical (i.e., foundations, architecture patterns, securing infrastructure, preparing for deployment), how it impacts the DevOps toolchain in a holistic manner, and how it can be used to build solutions specific to that vertical, with a detailed walkthrough of code, environments, and other tools.</p><p>With this solid base established, the book shares the importance, processes, and outcome of building infrastructure solutions. With this book, you would learn:</p><ul><li>Fundamentals of DevOps and Infrastructure-as-Code (IaC)</li><li>Prepare for the ever-evolving ecosystem of modular infrastructure and the needs of the future</li><li>Avoid potential pitfalls and breakdowns while working with infrastructure</li><li>Build scalable and efficient IaC solutions that work at a small, medium, and large scale in a real-life environment</li><li>Understand and be responsibly aware of security concerns related to the domain, and how to address them.</li></ul><p>With our sincere thanks to Apress team, Mark Powers, Spandana Chatterjee, Silembarasan Panneerselvam, Joseph Quatela, Shrikant Vishwakarma, Clement Wilson, technical reviewer Joaquin Gonzalez, experts from the industry who provided valuable insights, our mentors who guided us, and everyone involved.</p><p>Connect for more opportunities:</p><p><a href="https://www.linkedin.com/in/SnehPandya18">Sneh Pandya</a> | <a href="https://snehpandya.com/">Website</a> | <a href="https://topmate.io/SnehPandya18">Mentorships</a> | <a href="/service/mailto:hello@snehpandya.com">hello@snehpandya.com</a></p><p><a href="https://www.linkedin.com/in/riyagt/">Riya Guha Thakurta</a> | <a href="/service/mailto:riyaght2@gmail.com">riyaght2@gmail.com</a></p><p>This article was originally published on <a href="https://snehpandya.com/blog/book-author-sneh-pandya-launch-infrastructure-as-code/">Sneh Pandya’s Blog</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=60cc88c67f78" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Improve Performance in your iOS Applications — Part 3]]></title>
            <link>https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-3-dcb67fc1c365?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/dcb67fc1c365</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[performance-improvement]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Fri, 20 May 2022 00:00:00 GMT</pubDate>
            <atom:updated>2022-05-21T08:12:19.815Z</atom:updated>
            <content:encoded><![CDATA[<h3>Improve Performance in your iOS Applications — Part 3</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7_n5faXlb0j0lR-D.png" /></figure><p>Previously:</p><p><a href="https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-1-e773e18a4931"><strong>Improve Performance in your iOS Applications — Part 1</strong></a></p><p><a href="https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-2-67a0e8ec2886"><strong>Improve Performance in your iOS Applications — Part 2</strong></a></p><p>Although modern iOS devices are capable of handling a wide range of intensive and complex tasks, the device may seem slow if you are not paying close attention to how your application operates.</p><p>Performance improvements mentioned in this article are intended to make your code more readable and performant; however, select cautiously as per your needs. Oftentimes, altering or improving architecture and code refactoring takes more time and effort.</p><p>The <a href="https://blog.sentry.io/2022/04/07/improve-performance-in-your-ios-applications-part-1/"><strong>first article in the series</strong></a> showcases performance tips that help you improve compile time of your iOS apps, build apps faster and focus on iOS performance improvements in the build system, whereas the <a href="https://blog.sentry.io/2022/05/03/improve-performance-in-your-ios-applications-part-2/"><strong>second article in the series</strong></a><strong> </strong>talks about performance tips that help you improve the UI interactions, media playback, animations and visuals, etc. delivering a smooth and seamless experience.</p><p>The first step is always to enable optimization. Swift has three optimization levels:</p><p>-One: For regular development. It optimizes minimally and keeps all debug info.</p><p>-O: For most production code. Its extreme optimizations may substantially alter the nature and quantity of output code. Debug data will be lastly emitted.</p><p>-Osize: The compiler favors code size above speed in this mode.</p><p>The current optimization level may be changed via the Xcode UI:</p><p>Select the <strong>Project Editor</strong> icon in the <strong>Project Navigator</strong>. To access the project settings editor, click the icon beneath the Project heading. Change the <strong>Optimization Level</strong> box under the <strong>Build Settings</strong> heading to apply an optimization setting to all targets in the project.</p><p>Select the target under the <strong>Targets</strong> in the Project Editor and override the <strong>Optimization Level</strong> box under the <strong>Build Settings</strong> header.</p><h3>Understand Automatic Reference Counting</h3><p>If you want to build a high-performance iOS app, you will have to analyze how your components use memory and how to optimize it. The retain cycle problem is a typical memory management issue. But first, let’s examine how iOS handles its own memory.</p><p>Apple’s automated memory management system is called <strong>Automatic Reference Counting (ARC)</strong>. The reference count is used to determine whether or not a memory block should be deallocated. A new object’s reference count starts at 1. This reference count might change over time. Finally, when the reference count approaches 0, the object is freed.</p><h3>Strong and Weak References</h3><p>The above idea brings to the fact that you should also understand strong and weak references when declaring variables. By default, variables hold strong references to each other.</p><pre>struct Vehicle {<br>    var strongCar = UIView()<br>    weak var weakCar = UIView()<br>}</pre><p>The number of references grows as the variables get more powerful. When a reference count of two is set to a new strong variable, the reference count of the object increases to three.</p><p>On the other hand, weak factors have no effect on the increase in the reference count. If a reference count of two is assigned to an object that already has a reference count of three, the object’s reference count will stay at two.</p><p>Additionally, while a strong variable is active, the strong variable’s referenced component is guaranteed to remain in memory at the same time. On the other hand, this certainty will not apply to weak variables.</p><h3>Avoid Memory Leaks</h3><p>A model in which an entity Vehicle contains many instances of another entity Car, and each instance of an entity Car is connected with an entity Vehicle is most likely something you’ve seen before. In a very simplified implementation, it can look like this:</p><pre>class Vehicle {<br>    private var cars = [Car]()<br><br>    func add(_ car : Car) {<br>        cars.append(car)<br>    }<br>}<br><br>class Car {<br>    private var vehicle : Vehicle<br><br>    required init(vehicle : Vehicle) {<br>        self.vehicle = vehicle<br>    }<br>}<br><br>let vehicle = Vehicle()<br>let car = Car(vehicle: Vehicle)<br>vehicle.add(car)</pre><p>Everything looks good in the above example, but it really isn’t. Observe the similarities between the Vehicle and Cars: they both have a close connection with one another. Next, you’ll have to guess. A memory leak is to blame.</p><p>When a piece of data persists in memory after its intended lifespan has expired, we have a memory leak. When two strong variables address one another, they generate a memory leak. The retain cycle problem is the technical term for this issue. Then, let’s have a look at a few options.</p><h3>Make Use of Protocol Oriented Programming</h3><p>When it comes to storing data and modeling behavior in your applications, structures and classes are both excellent alternatives. However, because of their similarities, it may be tough to decide which is better.</p><p>Upon closer inspection of the code in the Standard Swift Library, it becomes clear that protocols are used rather often. Apple likes Protocol Oriented Programming and recommends that you use it if you are creating an inheritance connection from the beginning of your project.</p><p>Polymorphism is one of the most helpful parts of the OOP paradigm. It decides the runtime parameter or function to invoke. Dynamic Dispatch is the decision-making process. Below is a basic example of OOP. Class Car has an echo method with the override keyword since it is defined in superclass Vehicle. The echo method in class Car is called, not the echo method in class Vehicle.</p><pre>import UIKit<br><br>class Vehicle {<br>    func echo() {<br>        print(&quot;Improving iOS App performance.&quot;)<br>    }<br><br>    class Car: Vehicle {<br>        override fun echo() {<br>        <em>// your code</em><br>        }<br>    }<br>}</pre><p>Isn’t that great? No, as seen in the prior example, each runtime job slows down our execution time. So what’s the fix?</p><pre>import UIKit<br><br>class Vehicle {<br>    func echo() {}<br>}<br><br>class Car: Vehicle {<br>    func echo {<br>        <em>// your code</em><br>    }<br>}</pre><p>POP, which is an abbreviation for Protocol Oriented Programming, is now available. It took just a little tweak to significantly cut runtime computations. Isn’t it funny how familiar the POP terminology is? It is the most often used delegation pattern in Apple’s UIKit.</p><h3>Make Use of Static Dispatch</h3><p>While referring to Apple’s Swift Standard Library documentation, you would witness Structs, as opposed to classes, are of the value type, while classes are of the reference type. As a consequence, they may be used interchangeably. There seems to be a little change at first. This is much smaller than I expected!</p><p>Structs are allocated statically, as opposed to dynamically constructed classes, which are allocated dynamically. What happens, though, if a class has a struct-type parameter? So, what are you going to do? Stack allocation and struct construction are still required even if the struct argument is a structure. That is not at all the case! As a result, even if the argument is of type struct, the class that stores it allows it to be allocated in Heap and dispatched dynamically, independent of the argument’s type.</p><p>For the previously mentioned example, you can continue using the class you created earlier, but with the weak references of the variables:</p><pre>class Vehicle {<br>    private var cars = [Car]()<br><br>    func add(_ car : Car) {<br>        cars.append(car)<br>    }<br>}<br><br>class Car {<br>    private weak var vehicle : Vehicle?<br><br>    required init(vehicle : Vehicle) {<br>        self.vehicle = vehicle<br>    }<br>}<br><br>let vehicle = Vehicle()<br>let car = Car(vehicle: vehicle)<br>vehicle.add(Car)</pre><p>Finally, instead of employing extensive class inheritance in your code, try using structs and protocols.</p><h3>Restrict Variable Scopes</h3><p>A declaration that contains the private or fileprivate keywords limits the visibility of that declaration to the file in which it is included by those keywords. This enables the compiler to determine whether or not there are any additional possibly overriding declarations in the code.</p><p>Consequently, the lack of any such declarations allows the compiler to deduce the final keyword automatically and delete indirect calls for methods and field accesses as needed in the process. Using the following example, vehicle.doSomething() and car.myPrivateVar will both be able to be used directly, provided Vehicle and Car do not contain any overriding declarations in the same file:</p><pre>private class Vehicle {<br>  func doSomething() { ... }<br>}<br><br>class Car {<br>  fileprivate var myPrivateVar: Int<br>}<br><br>func usingVehicle(_ vehicle: Vehicle) {<br>  vehicle.doSomething() <em>// The compiler will remove calls to this method</em><br>}<br><br>func usingCar(_ car: Car) -&gt; Int {<br>  return car.myPrivateVar<br>}</pre><h3>Make Use of Value Types</h3><p>Swift has two types: <strong>value types</strong> (structs, enums, and tuples) and <strong>reference types</strong> (classes). It is vital to note that NSArrays cannot include value types. As a result, the optimizer may avoid most of the Array cost associated with dealing with the possibility that an array is backed by an NSArray when using value types.</p><pre><em>// Avoid using a class here.</em><br>struct Car {<br>  var name: String<br>  var manufacturedYear: [Int]<br>}<br><br>var newCar: [Car]</pre><p>Furthermore, unlike reference types, value types only need to count references if they contain a reference type recursively. To avoid unnecessary retain and release traffic in Array, value types might be used instead of reference types.</p><h3>Make Use of Closures</h3><p>When it comes to features, Swift’s closures are among the most robust currently available. They are, on the other hand, impervious to note retention cycles. Closures have the potential to cause retain cycles for one simple reason: they maintain a strong reference to the object that uses them while not in use.</p><p>In this example, we have a retention cycle that includes closures. <em>Note how the </em><em>self declarations are modified in the successive code blocks below:</em></p><pre>class Car {<br><br>    private var tyres = 0<br><br>    private var closure : (() -&gt; ()) = { }<br><br>    init() {<br>        closure = {<br>            self.tyres += 1			<em>// standard way</em><br>            print(self.tyres)<br>        }<br>    }<br><br>    func foo() {<br>        closure()<br>    }   <br>}</pre><p>The above example has a strong connection to the closure, which in turn has a strong connection to the object itself because self is used in the closure block. There are two options for dealing with this:</p><pre>class Car {<br>    private var tyres = 1<br>    private var closure : (() -&gt; ()) = { }<br><br>    init() {<br>        closure = { <br>[__unowned self__] in self.tyres += 1	<em>// unowned declaration</em><br>            print(self.tyres)<br>        }<br>    }<br><br>    func foo() {<br>        closure()<br>    }<br>}</pre><p>With the improvement above, the closer no longer has a strong reference. However, use [unowned self] with care, if the object has already been deallocated before the closure is called, a crash will result. For the same, you can also alter the implementation as below:</p><pre>class Car {<br><br>    private var tyres = 1<br><br>    private var closure : (() -&gt; ()) = { }<br><br>    init() {<br>        closure = { <br>[weak self] in self?.tyres += 1	<em>// weak declaration</em><br>            print(self?.tyres ?? &quot;&quot;)<br>        }<br>    }<br><br>    func foo() {<br>        closure()<br>    }   <br>}</pre><p>Here, [weak self] returns the same result as [unowned self] but it is handled optionally.</p><p>In the context of a closure, variables and constants from the surrounding scope are captured. This establishes a tight connection between it and the value required by the closure. In our project, it’s probable that we’ll have thousands of closures, which means that inspecting each and every one of them for memory concerns will be quite time-consuming. It is possible to monitor for memory leaks in Xcode; all that is required is to open Instruments and seek for the option Leaks.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*DWSBV-IRRsC-kB0_.png" /></figure><p>Navigate to Xcode and then <strong>Open Developer Tool</strong> → <strong>Instruments</strong> → <strong>Leaks</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qHR6JdzjGGpWgwGt.png" /></figure><p>Once opened, select the simulator and the application target and trace the leaks that need fixing.</p><p>As a best practice, when dealing with closures or delegates, it is best to utilize weak or unowned. Maintain a strong coding style in your project such that the presence of a weak self is immediately apparent. As soon as you&#39;re ready, go ahead and install <a href="https://github.com/realm/SwiftLint">SwiftLint</a>, a powerful tool for enforcing coding standards. For the benefit of the whole team, compiler-time problems may be spotted, and code style can be automated.</p><h3>Improve Utilization of Arrays</h3><p>Arrays often store their items in memory chunks that aren’t all adjacent. A new element in the array is simply added by allocating a new block and appending it to the array. This is excellent for adding, but less so for iterating. So, if you’re iterating over a huge array, ContiguousArray could be a good option.</p><p>When using ContiguousArray, it ensures that all of the array&#39;s entries are arranged sequentially. This is quite useful in locating the following piece of information. It&#39;s a trade-off, as always, and nothing magical happens. Because of the added limits on the array management in ContiguousArray, tasks like insertion and appending are now more difficult. As a result of our recent changes, your use case will no longer be limited.</p><p>Swift objects in general are so well-behaved that we can ignore memory problems and safety concerns while dealing with them since Swift handles everything for us. This has a negative impact on overall performance. You may use the withUnsafeBufferPointer function to acquire the array of pointers for the array elements, which enables you to trade off safety for performance. But you need to be careful, because if for some reason those elements are deallocated, it may lead to crashes.</p><p><a href="https://docs.sentry.io/platforms/apple/guides/ios/">Apple SDK for Sentry</a> allows you to monitor and track your app performance, user sessions, crashes that your users may face and more.</p><p>As a general rule, the issue in <a href="https://sentry.io/welcome/?utm_source=Sentry&amp;utm_medium=referral&amp;utm_campaign=ios-performance-3-sneh">Sentry.io</a> that captured this event should be available to examine. Errors resulting from other causes should not be displayed. To find them in Discover or on the Issues page, use the error search filter unhandled:true. Because sessions are not subject to data-rate, the number of unhandled events is not anticipated to match the number of failed sessions.</p><h3>Make Use of Generics</h3><p>Swift’s generic types provide a powerful abstraction tool. The Swift compiler constructs CustomFunc&lt;T&gt; with any value of T. Also required are a table of function pointers and a box containing T. This is due to the fact that CustomFunc&lt;Int&gt; behaves differently from CustomFunc&lt;String&gt;. Here is an example of a generic function:</p><pre>class CustomFunc&lt;T&gt; { ... }</pre><pre>CustomFunc&lt;Int&gt; X // Same function<br>CustomFunc&lt;String&gt; Y // Works for different data types</pre><p>Each time such code is invoked, Swift attempts to identify the concrete (non-generic) type being used. When the optimizer sees the generic function declaration and understands the concrete type, the Swift compiler may produce a variation of the generic function customized to that type. Specialization eliminates the administrative overhead of generics. Here are some more generics:</p><pre>class CustomStack&lt;T&gt; {<br>  func push(_ element: T) { ... }<br>  func pop() -&gt; T { ... }<br>}<br><br>func customAlgorithm&lt;T&gt;(_ a: [T], length: Int) { ... }<br><br>var stackOfInt: CustomStack&lt;Int&gt;<br><br>for i in ... {<br>  stack.push(...)<br>  stack.pop(...)<br>}<br><br>var arrayOfInt: [Int]   <em>// Compiler emits a specialized version for [Int] type</em><br><br>customAlgorithm(arrayOfInt, arrayOfInt.length)</pre><p>In order for the optimizer to conduct specialization, it must be possible for the generic declaration definition to be visible in the current Module. Unless the -whole-module-optimization switch is enabled, this can only occur if the declaration and invocation of the generic are both in the same file as the invocation of the generic.</p><p>The standard library is an exception to this rule. Definitions in the standard library are accessible for use in all modules and may be customized to meet specific needs.</p><h3>Optimize SpriteKit</h3><p>SpriteKit is a fast 2D framework that uses Apple’s Metal library to access the GPU directly. With a 120Hz display on devices like the iPad Pro, you need to work hard to maintain your frame updates inside the 8 milliseconds allotted.</p><p>Textures are expensive to load from your app package. Even if the image is modest, trying to load a full-screen background picture may cause you to go over your allotted time limit, resulting in missing frames. Make sure you preload textures in the background so that when you need them they’ll be ready to go in a jiffy. As a consequence, you have a substantially lower risk of losing frames.</p><p>Texture or animation hiccups and slow-moving UI elements irritate users and detract from the overall user experience. There are two ways to assess these sorts of experiences: slow and frozen frames. Both should be avoided if you want your app to perform properly. <a href="https://docs.sentry.io/platforms/apple/guides/ios/performance/instrumentation/automatic-instrumentation/#slow-and-frozen-frames">Sentry’s SDK</a> tracks the slow frames and frozen frames encountered during rendering on the devices.</p><p>Understanding that SKTexture is similar to UIImage in that it doesn’t really load data until required is critical to understanding how this works. Because of this, even for incredibly huge photos, this kind of code is almost instantaneous:</p><pre>let texture = SKTexture(imageNamed: &quot;Void&quot;)</pre><p>However, once that texture is assigned to a sprite node in your game scene, it must be loaded before it can be rendered. Ideally, you want that load to occur before the scene is shown — possibly in a loading screen — to minimize frame difficulties; thus, you should preload it like follows:</p><pre>texture.preload {<br>    print(&quot;Texture is ready!&quot;)<br>}</pre><h3>Use .replace instead of Blend</h3><p>A game’s rendering is one of the most time-consuming portions of development, even with all the computations required. It’s complicated as most sprites have irregular forms and alpha transparency, scenes normally have numerous layers, and effects frequently provide life to the scene.</p><p>You may prevent some of this by telling SpriteKit to render sprites without alpha transparency i.e., a solid form, or a backdrop picture as follows:</p><pre>yourSprite.blendMode = .replace</pre><p>In reality, this means SpriteKit doesn’t need to read the old color value and mix it with the new color value.</p><h3>Analyze Access Levels</h3><p>During the course of the program’s execution, the method call and parameter access of an object formed from a class remain unknown. This means that whenever you hit the run button in Xcode, the compiler starts up and does tasks like allocating memory and evaluating polymorphism use, among other tasks. Finally, the compiler indicates that a method or parameter is final if it cannot be accessed from beyond the program’s scope.</p><p>It is necessary to add the final keyword in the class declaration when you are aware that a class is not a basis for any other class. You include the final definition of a class in all of its arguments and methods when you add it to the class.</p><p>So, let’s imagine you want to override the behavior of a class. A consequence of this is that the final keyword is not allowed in this class. A new feature allows all parameters and methods that cannot be accessible by subclasses to be designated private.</p><h3>Conclusion</h3><p>Choosing whatever performance improvements to employ in any particular case might take some thought, testing, and experimenting, especially if we want our code to stay efficient as we add more data to it. A mixture of various performance improvement techniques, rather than simply one, may be required to obtain the desired performance characteristics. Expanding your understanding beyond Swift is often essential to determine the best format for each case.</p><p>In this article, you gained knowledge about improving iOS application performance for optimizing the existing codebase using the best practices, modularizing the architecture, and creating and utilizing reusable components in the code.</p><p>This is the third article in the <strong>Performance Series: Improve your iOS Apps</strong>. You can read about <a href="https://blog.sentry.io/2022/04/07/improve-performance-in-your-ios-applications-part-1/"><strong>the first article in the series</strong></a><strong> </strong>and <a href="https://blog.sentry.io/2022/05/03/improve-performance-in-your-ios-applications-part-2/"><strong>the second article in the series</strong></a><strong> </strong>about performance tips. Stay tuned for upcoming articles in the series, which will focus on UI improvements, code improvements, animations, visual experience best practices and much more.</p><p><em>Originally published at </em><a href="https://blog.sentry.io/2022/05/20/improve-performance-in-your-ios-applications-part-3/?utm_source=Medium&amp;utm_medium=referral&amp;utm_campaign=sneh-ios-performance-3"><em>https://blog.sentry.io</em></a><em> on May 20, 2022.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dcb67fc1c365" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Improve Performance in your iOS Applications — Part 2]]></title>
            <link>https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-2-67a0e8ec2886?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/67a0e8ec2886</guid>
            <category><![CDATA[performance-improvement]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Tue, 10 May 2022 00:00:00 GMT</pubDate>
            <atom:updated>2022-05-21T08:00:07.777Z</atom:updated>
            <content:encoded><![CDATA[<h3>Improve Performance in your iOS Applications — Part 2</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*2t39VXucmQAN9wTm.jpg" /></figure><p>Previously:</p><p><a href="https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-1-e773e18a4931"><strong>Improve Performance in your iOS Applications — Part 1</strong></a></p><p>Up next:</p><p><a href="https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-3-dcb67fc1c365"><strong>Improve Performance in your iOS Applications — Part 3</strong></a></p><p>The performance of your iOS app is crucial when building and publishing it for any number of users. Your users expect it to be delightful, fast and responsive, so if your app seems sluggish or unresponsive, it will affect your reviews and you might lose valuable users. While solving this for your apps, it’s easy to overlook the influence of the choices made on performance throughout development.</p><p>This is the second article in the series, which focuses on iOS performance tips that help you improve the UI interactions, media playback, animations and visuals, etc. delivering a smooth and seamless experience.</p><p>It is important to make sure there’s an issue to be fixed before attempting to optimize any code! Don’t fall prey to the temptation to “pre-optimize” your code, which is a mistake. Make regular use of Instruments to profile your code and discover any flaws. Matt Galloway has a nice lesson on how to optimize your code using Instruments.</p><p>Some of the suggestions made in this article may need a lot of effort to implement, or may make your code more difficult; thus select cautiously. Let’s dive right in.</p><p>You can read about <a href="https://blog.sentry.io/2022/04/07/improve-performance-in-your-ios-applications-part-1/"><strong>the first article in the series here</strong></a>, which focuses on performance tips that help you improve compile time of your iOS apps, build apps faster, and focus on iOS performance improvements in the build system.</p><p>Apple’s iOS App Store is a massive market with <a href="https://www.statista.com/statistics/268251/number-of-apps-in-the-itunes-app-store-since-2008/">millions of applications</a>, and it provides several opportunities for any organization or individual to develop and publish apps. However, with so many apps accessible, determining your “sweet spot” — the best place to attract new customers — may be difficult.</p><p>You must develop a set of indicators that will allow us to monitor your success against your objectives before you can expect to see an increase in your App Store revenue. Maintaining vigilance and knowing how your app will react when new features are deployed is critical after metrics and a clear aim for measuring performance have been defined.</p><p><a href="https://sentry.io/welcome">Sentry</a> is an essential monitoring tool to maintain the health and performance of your application code. Error Tracking and Performance Monitoring features enable you to see, correct, and learn about the applications from the frontend to the backend in a more clear, quick, and efficient way.</p><p>Sentry’s iOS performance monitoring for iOS applications allows you to determine the root of performance issues, such as slow API calls and database queries.</p><p>Setting up Sentry for your iOS application takes just a couple of steps once you <a href="https://sentry.io/signup">sign up</a>, also visible in the below image:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Kf8q3uGdnP5zVQ6h.png" /><figcaption>Sentry Dashboard</figcaption></figure><p>The <a href="https://docs.sentry.io/platforms/apple/guides/ios/#install">iOS SDK setup is required with the steps</a> in order to start receiving data on your Sentry dashboard to track, identify and resolve alerts and performance issues.</p><p>In this article, we will briefly understand how Sentry helps monitoring your iOS application performance.</p><p>Before going into the recommendations, it is important to define and understand how the main thread works, in order to optimize performance of the rendering UI.</p><p>As a rule of thumb, the main thread shouldn’t be used for very heavy tasks. Instead, it should mostly be used for actions like:</p><ul><li>Accepting user input and interactions</li><li>Displaying results and updating the UI</li></ul><p>Most of the time, the main thread processes too many things, which leads to loss or drop of frames. This happens when the device cannot process the standard frame rate and the user witnesses a lag or stuck screen.</p><p>So, it becomes important to identify which frames have been lost and which haven’t, but how?</p><p>There are times when it’s easy to spot them, because the most important thing is that they aren’t responding. Other times, it isn’t, and you need something more accurate to track them down. If you want to track them quickly, you can make use of profiling tools to identify the issue.</p><p>Once you identify the root causes behind the frames dropping, you can address them during your development. Here are some of the possibilities you can think of, to overcome frame-drops:</p><ul><li>Limiting the number of views being rendered on the mobile screen</li><li>Avoid transparency to elements wherever applicable</li><li>Reduce the amount of time and frequency of requested jobs</li><li>Decode JPEG images</li><li>Perform operations on background threads</li><li>Let’s go over them one by one.</li></ul><h3>How to Reduce View Hierarchy</h3><p>The easiest thing to start with is to reduce the number of views in the view hierarchy and avoid transparency wherever possible. To achieve the same, below code snippet helps drawing a white background which instructs the rendered to avoid any complex processing of transparency:</p><pre>label.layer.opacity = 1.0<br>label.backgroundColor = .white</pre><p>To verify the transparency overlapping issue is fixed, you can use the <strong>Color Blended Layers</strong> tool from Debug → View Debugging → Rendering menu in your Xcode.</p><h3>Reduce the Frequency of Operations</h3><p>Functions like cellForItemAt, indexPath, and scrollViewDidScroll must be very smooth and fast because they are called frequently, almost every moment, so they need to be very quick.</p><p>You should always make sure you have the <em>simplest views</em> and cells you can create and maintain. You should also make sure the configuration methods you use are always very light, such as layouts with constraints.</p><h3>Decode Images</h3><p>When it comes to missing frames, one of the most common culprits is <em>image</em> <em>decoding</em>. Typically, imageViews do this process on the main thread, behind the scenes. However, this might occasionally cause a continuous slowness in your apps, particularly when the images are rather large in size or resolution.</p><p>One solution to this issue is to delegate the decoding task to the background thread or queue. The operations will not be as efficient as the UIImageView’s standard decoding, but the mainThread will be free.</p><p>In this approach, it is important to sync specific updates, such as errors or warnings, because they are handled by the main thread and the image processing happens on the background thread to avoid any glitches, or crashes.</p><p><strong><em>Bonus Tip: Handle App in Background</em></strong></p><p><a href="https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background">Official documentation from Apple Developer</a> indicates that you should prepare your app to run in the background. Even the simplest instances when the user exits a foreground app, your app moves to the background before UIKit suspends it. According to the documentation guidelines, when your app is in the background, it should do as little as possible, and preferably nothing.</p><p>In such cases, all the processes including non-main thread operations, should also release resources in use — without hurting your app’s performance. When your app goes in the background, UIKit calls one of the following methods of your app:</p><ul><li>sceneDidEnterBackground(_:) method of the appropriate scene delegate for apps that support Scenes</li><li>applicationDidEnterBackground(_:) method for all other apps</li></ul><p>The good thing is, you don’t need to discard the images that you loaded from your application’s asset catalog.</p><p><strong><em>Bonus Tip: Scaling Images</em></strong></p><p>A UIImageView can only display images that have the same dimensions as the UIImageView. A UIImageView encased in a UIScrollView makes zooming in and out of photographs on the fly expensive.</p><p>It is possible to use a background thread to scale the image <em>after</em> it has been downloaded and used in the UIImageView if it is loaded from a remote service and you do not have control over its size before downloading.</p><h3>Perform Optimized Operations</h3><p>When dealing with certain properties of our UI Items, you may have encountered some off-screen rendering difficulties since you must prepare such elements before exposing them. In other words, it makes extensive use of the CPU and GPU. So, how can you identify this issue?</p><p><strong>Color Offscreen-Rendered Yellow</strong> comes handy! You can find the same under Debug → View Debugging → Rendering menu.</p><p>With this tool, you can identify the elements in the yellow or red color depending on how resource-heavy they are.</p><p>A common example such as the use of cornerRadius property indicates something like this in your app:</p><p>imageView.layer.cornerRadius = imageHeight / 2.0</p><p>The above line of code results in a 50% more resource-heavy operation per image. To avoid this, you should adapt to the below performance best practices:</p><ul><li>Avoid use of CornerRadius property, replace it with other approaches</li><li>Avoid use of ShouldRasterize property unless extremely necessary</li><li>Avoid use of Shadows in most of the cases, since it leads to off-screen rendering</li><li>Avoid use of boundingRectWithSize for text measurements since it leads to heavy processing</li><li>Make use of .rounded(), as they are lighter and less resource heavy while computation</li></ul><p>colorWithPatternImage from UIColor class is designed to generate small repeating pictures as backgrounds, if you want to utilize a full-frame background, you must use UIImageView. In this case, switching to UIImageView may result in considerable memory savings.</p><pre>UIImageView *bgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@&quot;background&quot;]];<br>[self.view addSubview:bgView];</pre><p>If your background is made up of small tiles, you should utilize the colorWithPatternImage function from UIColor class, which shows faster and consumes less memory.</p><pre>self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@&quot;background&quot;]];</pre><h3>Improve App Launch Time</h3><p>It’s a good idea to assess your iOS application launch time before making any optimizations. How much does your application take? There is a delayed starting time or are you OK with the existing threshold?</p><p>After you’ve done your research, you’ll want to determine an app’s realistic launch window. The initial frame of your app should take <strong>no more than 400 milliseconds</strong> to generate, according to <a href="https://developer.apple.com/videos/play/wwdc2019/423/?time=305">Apple at WWDC 2019</a>. If you have high hopes for your application, you should set this as a minimum goal.</p><p>There are three distinct types of launches:</p><p>When your application hasn’t been started in a long time or after a reboot, you may experience a “cold startup.” After a cold launch, each subsequent launch is referred to as a warm launch. System-side services are currently running and your program has already been brought into memory. Restarting your application from the home screen or the application switcher will resume your previous launch. We don’t have to wait long for your application to go live since it’s already operating!</p><p>To examine how your code influences startup time, use Xcode’s App Launch Time template. Using the template gives us an overview of the life cycle of the app when it is initially published. This is an excellent method for gaining early insight into which stages are generating the greatest delays. Instruments are particularly useful for honing in on code that is creating performance issues.</p><p>Sentry tracks application performance, measures metrics like throughput and latency, and displays the impact of errors across multiple services while capturing distributed traces consisting of transactions and spans to measure individual services and operations within those services.</p><p>For iOS, Sentry allows different SDK installation methods including <a href="https://docs.sentry.io/platforms/apple/install/cocoapods/">Cocoapods SDK</a>, <a href="https://docs.sentry.io/platforms/apple/install/swift-package-manager/">Swift Package Manager</a> and <a href="https://docs.sentry.io/platforms/apple/install/carthage/">Carthage</a>. The SDK is also capable of measuring app start activity, spanning different phases from the application launch to the first auto-generated UI transaction.</p><p>Application start metrics track how long your mobile application takes to launch. For this, Sentry measures cold starts and warm starts. The beginning of the app start is marked by the process start time, while the ending is marked by UIWindowDidBecomeVisibleNotification. The following are generated as a result:</p><ul><li><strong>Pre main</strong>: From the beginning of the process time to the runtime init.</li><li><strong>UIKit and Application Init</strong>: From the runtime init to the didFinishLaunchingNotification.</li><li><strong>Initial Frame Render</strong>: From didFinishLaunchingNotification to UIWindowDidBecomeVisibleNotification.</li></ul><p>The below image showcases the performance trace of an iOS application:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fcDaLbvEZi8WZOxH.png" /><figcaption>Sentry Performance Tracing View</figcaption></figure><p>You can click on each of the events under ui.rendering to get more details and find out which events or elements are causing performance issues.</p><h3>Lazy Load and Reuse Your Views</h3><p>Those who have a lot of views nested within UIScrollView consume more CPU and memory than people whose applications don&#39;t have a lot of views. The idea is to duplicate the behaviours of UITableView and UICollectionView.</p><p>Instead of creating all of the subViews at once, create them as required and place them in a queue when they’re done.</p><p>This way, you only need to create views when someone scrolls, which saves memory. The energy efficiency problem that arises while creating views impacts other aspects of your software as well. Assume a user hits a button and wants to display a view. There are two options:</p><ul><li>As the screen loads, create and conceal the view, then reveal it when required</li><li>Make and display items as required</li></ul><p>The first method has the advantage of requiring you to establish a <em>viewpoint</em> from the outset and maintain it until it is no longer required. This option consumes more memory than the second. Because when a user hits a button, your programme merely has to re-enable the view. The second option is the inverse — it uses less memory but runs somewhat slower when the button is pressed.</p><p>In such scenarios, Mobile Vitals Provides you information on your iOS app, allowing you to prioritize significant problems and quickly resolve them. Sentry detects sluggish frames and frozen frames to track user interface responsiveness. A phone or tablet typically renders 60 fps, which boils down to each frame being rendered at 16.67 ms.</p><p>Apple can use a faster frame rate, particularly as 120 fps panels become more common. Sentry detects the frame rate and changes the slow frame calculation for these programmes. In the example below, the transaction detail view shows the sluggish, frozen, and total frames:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kLV6r5mM_D8lLVla.png" /></figure><h3>Reuse Identifiers to improve performance</h3><p>Setting the wrong reuse identifier for UITableViewCells, UICollectionViewCells, or even UITableViewHeaderFooterViews is a common application development mistake. The data source should often reuse UITableViewCell instances when allocating cells to rows in a tableView.</p><p>Without the reuseIdentifier, each time a table view is presented, a new cell must be set on the UI. This may have a major influence on performance, particularly the app&#39;s scrolling experience. In addition to UICollectionView cells and supplemental views, reuseIdentifiers should be used in header and footer views.</p><p>If required, this procedure removes cells from the queue or generates new cells with previously registered NIBs or classes. If there are no reusable cells and no classes or NIBs have been set up, this method returns nil. Sentry allows you to set up alerts with real-time insights into errors, problems or even custom defined criteria that you can specify for your own applications:</p><ul><li>New issues emerging</li><li>Increasing frequency of issues</li><li>Resolved or ignored issues in the past becoming unresolved and resurfacing again</li></ul><p>You can also define alerts and receive notifications for a specific failure rate, latency of the action, and so on. You can create and manage alerts from the Alerts page on Sentry dashboard.</p><p>By default, Sentry will provide a considerable quantity of data as part of the problem notice. In certain circumstances, this data may be source code or other user data. Enabling the Enhanced Privacy option will allow you to regulate this. To do so, visit your organization’s dashboard, select Settings, and then check the option to allow increased privacy. Email alerts and other elements of the system will begin limiting data to the issue’s title and description as soon as you activate this option.</p><h3>How to Further Improve UI Scroll</h3><p>If the user experience stutters when scrolling in the complex hierarchy such as Table view, make sure you perform the following to keep the table View scrolling smoothly:</p><ul><li>reuseIdentifier in the proper manner when reusing cells</li><li>Make all the views opaque, including the cells</li><li>Avoid using gradients, zooming, or selecting a backdrop color.</li><li>Use asynchronous loading and caching if the data in the cell is retrieved from the Internet.</li><li>shadowPath should be used to draw a shadow, only when necessary.</li><li>Avoid using subviews as much as possible.</li><li>Avoid using applycellForRowAtIndexPath. If you need to use it, do it just once and save the results in a cache.</li><li>Provide userowHeight.section a fixed height and avoid requests to the delegate while setting the height.</li></ul><h3>Caching to the Rescue</h3><p>On iOS, there are various ways to build a visually appealing UI. Full-size pictures or resizable images may be used, and they can be rendered using CALayer, CoreGraphics, or even OpenGL. Each solution, of course, differs in terms of complexity and performance.</p><p>Utilizing pre-rendered graphics saves time by eliminating the need for iOS to create a picture, draw on it, and then display it on the screen The problem is that you must include all relevant photographs in your program bundle, which increases its capacity — which is why using variable-sized images is even better: you can save unnecessary space and avoid developing distinct images for different portions of your application, for example buttons.</p><p>Using images, on the other hand, means you lose the ability to change usability of the image, you will have to redo them repeatedly, which costs time and resources and if you want to create animation effects, even if each image represents only a small portion of the changes, you will need a large number of images, which increases the bundle size.</p><p>As a general trade-off, balancing performance against managing the growing bundle size is advisable.</p><p>One of the most popular methods to load an image from a bundle is imageNamed, the other one is image with content file, which is less common.</p><p>When images are loaded, imageNamed saves them in a cache. It searches the system cache for an image object with a specified name and returns it if it is found. Objects that don&#39;t have a matching picture in the cache are fetched from the provided document and then cached and returned using this function. imageWithContentsOfFile, on the other hand, just loads pictures.</p><p>The question is, how do you choose which one to use?</p><p>If you’re just going to utilize heavy images once, there’s no need to cache them. Instead, use an image with a <em>Content file</em> and save yourself the memory. ImageNamed, on the other hand, is a superior option in situations when images are often re-used such as lists.</p><h3>How to Display Shadows Efficiently</h3><p>To cast a shadow on a layer or view, usually developers choose the QuartzCore framework like below example:</p><pre>#import &lt;QuartzCore/QuartzCore.h&gt;</pre><pre>UIView *view = [[UIView alloc] init];<br>view.layer.shadowOffset = CGSizeMake(-1.0f, 1.0f);<br>view.layer.shadowRadius = 5.0f;view.layer.shadowOpacity = 0.6;</pre><p>This seems a lot easier for the system to represent. Isn’t it? Sadly, the above strategy is flawed. So Core Animation must first execute an offscreen pass to identify your view’s exact shape, which is resource heavy.</p><p>Using shadowPath takes care of the issue:</p><pre>view.layer.shadowPath = [[UIBezierPath bezierPathWithRect:view.bounds] CGPath];</pre><p>With shadowPath, iOS no longer has to recalculate how to draw each time. Instead, it utilizes a previously determined route. Problems arise when you have to calculate and update the shadow path manually in certain views, and this is time-consuming.</p><h3>Be Aware with Memory Warnings</h3><p>iOS notifies all running applications when the system memory is low. When your app receives a memory warning, it must clear up as much memory as possible. That is in accordance with the guidelines established by the Apple team. The most efficient way to do this is to remove strong references to reusable caches, image objects, and other stuff. UIKit, for the most part, makes it simple to keep track of low memory notifications.</p><p>On the other hand, Sentry adds breadcrumbs prior to an issue developing. As is the case with traditional logs, these events may include a plethora of structured data. You can allow the SDK to automatically capture the breadcrumbs for your app such as click and keypress events, or manually add a breadcrumb for specific actions performed using the code below:</p><pre>import Sentry<br>let breadcrumb = Breadcrumb()<br>breadcrumb.level = SentryLevel.info<br>breadcrumb.category = &quot;auth&quot;<br>breadcrumb.message = &quot;Authenticated user \(user.email)&quot;<br>SentrySDK.addBreadcrumb(crumb: breadcrumb)</pre><p>You can refer to <a href="https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/">this documentation</a> to understand and configure the data and properties of a breadcrumb. After obtaining these alerts from the system, you should remove any unnecessary objects from the memory. Furthermore, it is possible to erase images from an app’s image cache that are not currently shown on the screen. If you do not handle memory alerts in this way, the operating system may shut down your app. To free up memory, the object must be able to be recreated. When creating, keep a watch out for emulation-based rendering.</p><p>For end-users, the response time is crucial as delays or unresponsiveness due to memory overflow and other things may frustrate the user, resulting in the user abandoning the app altogether.</p><p>Sentry Metrics provide you a better understanding of how your users are interacting with your app. You can quantify the health of your app more quickly and discover faults or performance concerns that may be developing, such as <a href="https://docs.sentry.io/platforms/apple/configuration/out-of-memory/">out of memory errors (OOMs)</a>.</p><p>Before your app terminates, the Apple SDK writes a report to disc with data like the stack trace, tags, and breadcrumbs. This is because OOM crashes force the OS to stop your software without notice. It’s not easy to get the app’s state back after an OOM. So we’d need to routinely store the app state. This would generate a lot of I/O, slowing down the application. OOM occurrences lack context.</p><h3>Managing -Legacy Projects</h3><p>Storyboards have replaced XIBs as the main visual design tool in iOS 5. While XIBs might be advantageous in certain situations, they are not always required. You’ll have to deal with them unless you’re targeting pre-iOS 5 devices or utilizing a custom reusable view.</p><p>If you must utilize XIBs, keep them as simple as possible. If a view controller’s view hierarchy necessitates the creation of many XIBs, construct one for each XIB. Any images included inside the XIB are also included in the memory load and should be considered. Remove any views that aren’t presently being used to conserve memory. Storyboards prevent this from occurring since they only build view controllers when they are absolutely necessary.</p><p>When you load a nib file that contains references to an image or sound resource, the nib-loading process loads and caches the actual image or sound file. OS X saves picture and sound resources in temporary caches so that they may be accessed later. On iOS, named caches only store picture resources and no other sorts of data. Depending on your platform, the imageNamed: method of NSImage or UIImage may be used to obtain images.</p><p>Sentry identifies transactions that have had significant changes in their performance over time with Trends. This view is ideal for providing insights when you have transactions with large counts. You can access the Trends View from the Performance homepage by clicking the tab in the top right corner of the page. Over time, this page highlights deals that have seen notable changes to their profitability.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rmDZTaZ1LBjtMQp6.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CF2cFOqi6YdBMK9a.png" /></figure><h3>Conclusion</h3><p>Despite the importance of application performance, it is often disregarded by developers. As a result, we tend to only use the most powerful devices and the most expensive data plans while developing our applications. As a result, we are blind to the consequences of our underperformance.</p><p>In this article, you gained knowledge about improving iOS application performance for UI, animations and more. This article tries to ensure all the UI updates, frontend rendering, animations and how <a href="https://sentry.io/welcome/?utm_source=Medium&amp;utm_medium=referral&amp;utm_campaign=ios-app-sneh">Sentry</a> can help you supercharge your performance improvement journey.</p><p>This is the second article in the <strong>Performance Series: Improve your iOS Applications</strong>. You can read about the <a href="https://blog.sentry.io/2022/04/07/improve-performance-in-your-ios-applications-part-1/"><strong>first article in the series</strong></a>, which focuses on performance improvements for iOS build processes and build systems. Stay tuned for upcoming articles in the series, which will focus on UI improvements, code improvements, animations, visual experience best practices and much more.</p><p><em>Originally published at </em><a href="https://blog.sentry.io/2022/05/10/improve-performance-in-your-ios-applications-part-2"><em>https://blog.sentry.io</em></a><em> on May 10, 2022.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=67a0e8ec2886" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Improve Performance in Your iOS Applications — Part 1]]></title>
            <link>https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-1-e773e18a4931?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/e773e18a4931</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[performance-improvement]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Thu, 07 Apr 2022 09:32:00 GMT</pubDate>
            <atom:updated>2022-05-21T08:01:57.960Z</atom:updated>
            <content:encoded><![CDATA[<h3>Improve Performance in Your iOS Applications — Part 1</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*VnzQnLu-cgf05fAz.jpg" /></figure><p>Up next:</p><p><a href="https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-2-67a0e8ec2886"><strong>Improve Performance in your iOS Applications — Part 2</strong></a></p><p><a href="https://snehpandya18.medium.com/improve-performance-in-your-ios-applications-part-3-dcb67fc1c365"><strong>Improve Performance in your iOS Applications — Part 3</strong></a></p><p>Since inception back in 2007, Apple and the iOS ecosystem has drastically improved with a plethora of changes and new features added (or removed) over time. At the same time, the size of the applications and the data has consistently grown. This has its own impact on the powerhouse in your hand — the iOS device.</p><p>Developers strive to design the best experience, often compromising speed and performance. This can ultimately lead to application performance degrading over time and result in bad user experiences, or even worse — users deleting your iOS applications. To address this, we are introducing a 4-part performance series focused on improving your iOS applications.</p><p>In this first article, we’ll focus in on iOS performance tips that help you improve the compile time of your iOS applications, build faster, and hone in on iOS performance improvements in the build system. Let’s dive right in.</p><h3>Building Only The Necessary</h3><p>Let’s start with a one-line tweak that would slash most of your build times in half.</p><p>Did you know that all of your files get built multiple times? One important observation in Xcode has an answer to this. This relatively old <a href="https://stackoverflow.com/questions/29683136/xcode-6-3-builds-all-swift-files-twice">Stack Overflow article</a> still stands applicable for the latest version of Xcode.</p><p>The solution is: For all non-necessary or non-release build types In your Xcode, set <strong>Build Active Architectures Only</strong> to <strong>Yes</strong>. Because build settings generally have more than just Release and Debug settings (unlike most projects), you might see this flag enabled for all of the configurations you utilize for development by default.</p><p>To update the setting, you need to navigate to the project file in the Project navigator, then select your project on the left sidebar and navigate to the Build Settings tab. Under Architectures, you will find the setting of <strong>Build Active Architectures Only</strong> which you need to change to <strong>Yes</strong>.</p><p>This should ideally reduce your build time to 50% in a majority of the cases, but may vary on the basis of app architecture and other configurations. Fantastic, isn’t it? Let’s move on to the next one.</p><h3>Speed up Compile Time for Swift</h3><p>Did you know that, by default, <strong>Whole Module Optimization</strong> also impacts your build generation and build speed? By default this is only enabled for <em>release</em>.</p><p>Here’s how to tweak it:</p><p>For <em>debug</em> mode, <strong>enable</strong> the <strong>Whole Module Optimization</strong> module under Swift Compiler - Code Generation setting and then under <strong>Other Swift Flags</strong>, specify below flags for the <em>debug</em> mode:</p><p>Also, set the value of <strong>Optimization Level</strong> to Fast, Whole Module Optimization under the debug build settings.</p><p>If you use CocoaPods, adding the below code at the bottom of your Podile will help optimize all of your dependencies:</p><pre>post_install do |installer|<br>  installer.pods_project.targets.each do |target|<br>    target.build_configurations.each do |config|<br>      if config.name == &#39;Debug&#39;<br>        config.build_settings[&#39;OTHER_SWIFT_FLAGS&#39;] = [&#39;$(inherited)&#39;, &#39;-Onone&#39;]<br>        config.build_settings[&#39;SWIFT_OPTIMIZATION_LEVEL&#39;] = &#39;-Owholemodule&#39;<br>      end<br>    end<br>  end<br>end</pre><p>This will ensure that the entire module is compiled at once without optimizing the code for debug builds for faster development and saving time.</p><h3>Analyzing Your iOS Build Time</h3><p>Many developers face issues where their code is taking relatively longer to compile than it should. The more concerning fact is, sometimes it suddenly gets slower than the previous build times. This can escalate rather quickly. This technique can help you in locating sections of code that the compiler is having difficulty with, and you can try reordering them to speed up compilation.</p><p>The first step is to navigate to your Swift Compiler section and add the below flags under <strong>Other Swift Flags</strong>:</p><p>-Xfrontend-debug-time-function-bodies</p><p>With the above flags, the compiler prints out how much time it takes for each function. The next step is to collect all of these log data points and sort them out. The output will give you filename and line numbers. In most of the cases there are only a few functions (sometimes even less than 5) being printed repeatedly — so don’t worry.</p><p>Remember, you don’t need to know a lot about compilers to understand or make sense of the log outputs. Just observe the function names and keywords at the end of each line and it will make sense.</p><p>Rewriting just a couple of lines of code may end up building your entire project 50% faster. This is because in most of the cases, the error lines showcase the improvements specific to data structures and how to write more appropriate code.</p><p>Simply rewriting the functions to be as fundamental as you can may solve the problem — ostensibly unnecessary type definitions, intermediate variables, mutable variables, etc. This is a simple yet <a href="https://twitter.com/benjaminencz/status/685510563015741440">excellent example of the same</a>.</p><h3>Upgrade Your System Config</h3><p>Above Xcode 9.2, the newly introduced architecture allows projects to run Swift build tasks in parallel. If your machine does not have enough RAM, build times can slow down drastically. You can do a few things to avoid this:</p><ul><li>Disable the parallel task execution for your Xcode using the below command:</li></ul><p>defaults write com.apple.dt.Xcode BuildSystemScheduleInherentlyParallelCommandsExclusively -bool NO</p><ul><li>Some of your projects will run faster and better than others. Another thing to note: if your machine doesn’t have a lot of RAM, this may actually slow your builds down. If applying the above makes your builds slower, you should ideally disable concurrent build tasks using the following command:</li></ul><p>defaults delete com.apple.dt.Xcode BuildSystemScheduleInherentlyParallelCommandsExclusively</p><ul><li>If you have a superfast configuration on your machine which can speed up your build time, you might want to consider allocating a few extra processes Xcode by making use of command below:</li></ul><p>defaults write com.apple.Xcode PBXNumberOfParallelBuildSubtasks 4</p><ul><li>In your workspace settings or project settings, enable the <em>new build system</em> under <strong>Shared Workspace Settings</strong> to speed up your builds. Once selected, the new build system takes control of compilation and build generation, reducing the time it takes to compile your Swift code.</li><li>Increase your RAM or upgrade your system hardware (M1 is blazing fast).</li></ul><h3>Improve iOS Build Processes</h3><p>If parallel builds are enabled for your project, you will witness better build performance and the order of the build targets will not matter as much. However, if parallel build generation is turned off using the above technique, Xcode attempts to build the <em>target dependencies</em> in the order specified under the build action scheme.</p><p>In such cases, you can declare the input and output configuration to let the build system know which script tasks to avoid rerunning unnecessarily.</p><p>Another technique you can incorporate in your workspace is to <strong>avoid auto linking project dependencies</strong>. This particular setting lets the compiler automatically link the framework’s associated with the modules you have imported without explicitly linking them in your link library’s build phase. However, auto-link itself <em>does not establish dependency</em> on the specified framework at the build system level. This means, the build system or the auto-link feature does not guarantee that the target your project depends on is actually built before you try to link the dependencies.</p><p>Instead, you should add explicit dependencies to let the build system know, and you may also prefer to reference projects by drag-and-drop technique with other Xcode projects into your <em>current project</em> ‘s file navigator and capture the targets of other projects that are required.</p><h3>Optimize iOS Crash Report Generation</h3><p>iOS generates a dSYM file to maintain the mapping between the original code and the obfuscated stack trace to understand the crash reports. Since dSYM file generation takes a good amount of time, you can avoid generating dSYM in cases when the debugger is not attached, or during the debug build generation.</p><p>Under <strong>Debug Information Format</strong> settings, make sure you’re using plain <strong>DWARF</strong> instead of <strong>DWARF with dSYM File</strong>.</p><h3>Objective-C Headers Are the Culprit</h3><p>For legacy projects, you might have noticed that many of the project files start with exhaustive header declarations. Did you know that declaring <em>extra</em> or <em>unnecessary</em> header imports in the project can drastically slow down the build generation time?</p><p>Moreover, a large number of header files also contribute exponentially to the time required for dependency checking.</p><p>In such cases, the below strategies come in handy:</p><ul><li>Reduce header imports to only the necessary ones; you can identify this easily using code compile and lint-checking tools such as SwiftLint</li><li>Make use of <em>forward declaration</em> instead of recursive header inclusion or header file calling another header file to drastically reduce the number of dependencies and ultimately improve the build generation time (<a href="https://tyciphonedevelopment.blogspot.com/2008/11/objective-c-forward-declaration.html">this link should be helpful</a>).</li></ul><h3>Reduce Using Non-Opaque Views</h3><p>An opaque view is the view that does not have transparency. This means that any elements placed behind the opaque view are hidden behind the layer.</p><p>While focusing on iOS performance improvements, this is a key area which everyone needs to understand. Setting a view to <em>opaque</em> ensures that the system optimizations are applied before the framework draws the view and surely some improvements can be witnessed, specifically drawing performance while rendering the screen.</p><p>If any view has a transparency or alpha channel below 1.0, the iOS framework has to put extra effort to calculate the final display render by blending different views and layers together while processing the view hierarchy. On the contrary, if any view has an opaque property set, the iOS framework just super-imposes this view layer above the previous ones and avoids any extra processing to blend the view hierarchy.</p><p>To check the opaque and non-opaque view hierarchy, you can navigate to iOS Simulator → Debug → Color Blended Layers.</p><p>Once enabled, you will be able to see <em>red</em> and <em>green</em> layers being drawn on the screen. The green layers indicate that the view is <em>opaque</em> and no blending is applied to render it, whereas the red layers indicate the view is <em>non-opaque</em> and is drawn after the layers have been blended.</p><p>You can optimize iOS app performance by reducing the highlighted views with red as much as possible by applying the below code snippet:</p><p>label.backgroundColor = UIColor.clear // Originallabel.backgroundColor = UIColor.white // To be applied</p><p>Also, to remove alpha channel from the images, you can make use of the <strong>Preview app</strong>. All you need to do is duplicate the image by pressing Shift + CMD + S and unchecking the <strong>Alpha</strong> checkbox while saving the duplicate image.</p><h3>Tweak Your Swift Extensions</h3><p>When you’re writing your own extensions in Swift, by default, they are set to public access modifiers. This increases the compilation time as it is meant to be utilized by every Swift class.</p><p>The best way to tackle this is by completely avoiding the creation of extensions. If not, then you should create the extensions and set the access modifier to private as you would only be using them in one part of your code.</p><h3>Remove Unnecessary and Unused Code</h3><p>Be it pods or the code which is not serving any purpose in your iOS application any longer, removing the unused code, unused image files or assets, many pods or even the functions that are no longer used would drastically reduce the build time — as well as reduce the size of your release build.</p><h3>Make Your iOS App Modular</h3><p>For relatively large projects, and depending upon the requirements, one of the most effective solutions to improve your iOS app performance is to convert the mammoth iOS project into a modular structure. For such large projects where there are multiple features and functionalities, you can consider a modular architecture where each module consists of consolidated features which relate closely with each other in the same module.</p><p>The idea is to replace the project with a workspace and build modules that can be compiled and injected into the workspace for utilization. Generally, adhering to separation of concerns, you can modularize your iOS apps in a few modules such as <em>database</em>, <em>network</em>, <em>utilities</em>, <em>interface</em>, etc.</p><p>The advantage of modularizing your iOS app is not only reduction in compilation time, but you can easily reuse the modules across the project as well as in other projects just by importing them instead of re-writing the entire code every time.</p><h3>Make Use of Caching</h3><p>With the approach to <em>Build once, reuse everywhere</em> — a remote build caching strategy helps reduce build times drastically since you no longer need to rebuild anything that has been built on any machine.</p><p>In this approach, artefacts generated and shared from another computer can be downloaded instead of generating a target locally as long as all input files and compilation settings are the same. Finding the proper cache level is critical to the success of remote caching. Excessively granular caching units, which cache every stage of the compilation process, may result in significant network traffic overhead, outweighing the CPU savings. Putting the entire software into a single cacheable unit, on the other hand, may reduce the caching hit rate significantly; every single local update invalidates remotely accessible cache artefacts, forcing a complete build locally.</p><p>Another way to make the best use of caching is by using the <a href="https://bazel.build/">Bazel build system</a>. For iOS, Bazel comes with a predefined set of Apple rules that help you get started and build a complete application. However, please note that setting up Bazel and successfully running your iOS build with Bazel requires advanced level understanding, but in my opinion it’s worth it, especially for large scale projects. A few key organizations including Lyft, Pinterest, and LinkedIn make use of Bazel to build their iOS apps as well.</p><p>Thanks to Bazel, build only gets performed once and rebuild is only performed when any of the target files change. Once you point it to a remote cache with -remote_http_cache, we can share this artifact in a shared remote cache. You can learn more about setting up Bazel for your iOS apps <a href="https://blog.allegro.tech/2020/12/speeding-up-ios-builds-with-bazel.html">here</a> and <a href="https://engineering.linecorp.com/en/blog/improving-build-performance-line-ios-bazel/">here</a>.</p><h3>Tweak Your iOS App Test Setup</h3><p>Apple iOS test simulator can be used to conduct app tests on a variety of software and hardware combinations. By choosing <em>Physical Size</em> or <em>Pixel Accurate window size</em> for the simulator, you may reduce the number of tests you run and the time it takes to perform them. These configuration changes use fewer resources and prevent tests from being slowed down by simulating pixels that will never be seen.</p><p>Here’s a <a href="https://stackoverflow.com/questions/18606926/adjusting-the-xcode-iphone-simulator-scale-and-size">Stack Overflow answer</a> on how to configure your iOS simulator for both <em>Physical Size</em> or <em>Pixel Accurate window size</em> to make use of iOS performance testing tools.</p><h3>Monitor Your iOS Performance with Sentry</h3><p>Sentry’s iOS SDK reports errors automatically whenever an error(s) or exception(s) goes uncaught in your application causing the application to crash. The minimum version required to integrate Sentry on iOS is 9.0.</p><p>While the recommended way of installing the SDK using Cocoapods is shown below, the <a href="https://docs.sentry.io/platforms/apple/guides/ios/install/">alternate installation methods</a> are also supported for iOS apps:</p><pre>platform :ios, &#39;9.0&#39;<br>use_frameworks! # This is important<br><br>target &#39;YourApp&#39; do<br>  pod &#39;Sentry&#39;, :git =&gt; &#39;https://github.com/getsentry/sentry-cocoa.git&#39;, :tag =&gt; &#39;7.11.0&#39;<br>end<br><br>#run pod install</pre><p>Once installed, you can set up the configuration for your iOS apps <a href="https://docs.sentry.io/platforms/apple/guides/ios/#configure">using the documentation guide</a>.</p><p>With performance monitoring, Sentry tracks your software performance, measuring metrics like throughput and latency, and displaying the impact of errors across multiple systems.</p><p>iOS Performance monitoring with the help of Sentry is possible in two ways:</p><ul><li><em>Automatic instrumentation</em> allows you to capture standard tracing already specified and supported by Sentry such as capturing transactions on app load, or when the app starts including both cold start and warm start, detecting slow and frozen frames, network calls, file and I/O operations and much more. You can enable automatic instrumentation by <a href="https://docs.sentry.io/platforms/apple/guides/ios/performance/instrumentation/automatic-instrumentation/">following the steps given here</a>.</li><li><em>Custom instrumentation</em> allows you to specify your own implementation and create transactions to capture possibly every action possible. This can vary from case to case, feature to feature, such as when a user performs a checkout on the cart, or validating payment details, or signing up for the first time ever, and so on. You can enable custom instrumentation by <a href="https://docs.sentry.io/platforms/apple/guides/ios/performance/instrumentation/custom-instrumentation/">following the steps given here</a>.</li></ul><p>Sentry supports a plethora of <a href="https://sentry.io/integrations/">integrations</a> to achieve your suitable target through different workflows and providers.</p><h3>Conclusion</h3><p>In this article, we walked through how to improve iOS application performance, iOS performance testing tools, iOS performance monitoring, and more. We focused on build processes and build system in general. While the effort has been to bring everything under one roof, the topic of iOS performance tips is vast and should be given proper justice.</p><p>Hence, this is the first of 4 articles in the Performance Series: Improve your iOS Applications. Stay tuned for upcoming articles in the series, which will focus on UI improvements, code improvements, animations, visual experience best practices, and more.</p><p><a href="https://sentry.io/welcome/?utm_source=Medium&amp;utm_medium=referral&amp;utm_campaign=ios-performance-1-sneh"><strong>Sentry</strong></a> is essential for monitoring application code health. From Error Tracking to Performance Monitoring, developers can see clearer, solve quicker, and learn continuously about their applications — from the frontend to the backend. Loved by over 1 million developers and more than <em>80,000 organizations worldwide</em>, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games.</p><p><em>Originally published at </em><a href="https://blog.sentry.io/2022/04/07/improve-performance-in-your-ios-applications-part-1/?utm_source=Medium&amp;utm_medium=referral&amp;utm_campaign=ios-performance-1-sneh"><em>https://blog.sentry.io</em></a><em> on April 7, 2022.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e773e18a4931" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Android Manifest Placeholders]]></title>
            <link>https://proandroiddev.com/android-manifest-placeholders-12f3743b920d?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/12f3743b920d</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[androidmanifest]]></category>
            <category><![CDATA[sentry]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Wed, 30 Mar 2022 00:00:00 GMT</pubDate>
            <atom:updated>2022-03-31T19:55:40.649Z</atom:updated>
            <content:encoded><![CDATA[<p>In this article, you will learn how to make use of Android Manifest placeholders to supercharge your Android app development.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*FJaj2l1UmtkMzGkR.jpg" /><figcaption>Android Manifest Placeholder</figcaption></figure><p>Android Manifest file is essential for any Android app, which contains specific information about your app, Android build tools, Google Play, device permissions, app launch information, operating system config and more. Every Android app must have an AndroidManifest.xml file in the directory structure.</p><p>Android Manifest usually contains pre-defined or static information which is then used to run the app. However, Android toolchain provides customization by allowing you to specify dynamic information through variable declaration, generally referred as <a href="https://developer.android.com/studio/build/manage-manifests#inject_build_variables_into_the_manifest">Android Manifest placeholders</a>. These variables are specified under the manifestPlaceholders block in your build.gradle file.</p><p>The variables are defined in key-value pairs and can be used for various purposes such as specifying custom configuration for your Manifest, managing configuration specific to build variant and more.</p><p>In this article, you will learn how to make use of Android Manifest placeholders to supercharge your Android app development.</p><h3>Injecting Variables into AndroidManifest.xml</h3><p>Let’s begin with the simplest case. When you need to specify a property such as a URL for your app’s network communication in your Manifest, you need to specify it in your build.gradle as below:</p><pre><em>// build.gradle</em><br>android {<br>  defaultConfig {<br>    manifestPlaceholders.baseUrl = &quot;api.demoserver.com&quot;<br>  }<br>}</pre><p>Here, the variable name is baseUrl whereas the assigned string is the value which will be received by AndroidManifest.xml once declared as below:</p><pre>// AndroidManifest.xml<br>&lt;intent-filter ...&gt; <br>  &lt;data android:scheme=&quot;https&quot; android:host=&quot;${baseUrl}&quot; ... /&gt;<br>&lt;/intent-filter&gt;</pre><p>Similarly, other examples can include properties such as applicationId, screenOrientation as well as frequently used elements in the AndroidManifest.xml:</p><pre><em>// build.gradle</em><br>android {<br>  defaultConfig {<br>    applicationId &quot;example.manifest.app&quot;<br>  }<br>  buildTypes {<br>    release {<br>      manifestPlaceholders.screenOrientation = &quot;portrait&quot;<br>    }<br>    debug {<br>      manifestPlaceholders.screenOrientation = &quot;unspecified&quot;<br>    }<br>  }<br>}</pre><p>Which can be used in your Manifest as below:</p><pre>// AndroidManifest.xml<br>&lt;intent-filter ... &gt;<br>  &lt;action android:name=&quot;${applicationId}&quot; /&gt;<br>&lt;/intent-filter&gt;<br>&lt;uses-sdk tools:overrideLibrary=&quot;${applicationId}.home, ${applicationId}.util&quot; /&gt;<br>&lt;activity<br>  android:name=&quot;.MainActivity&quot;<br>  android:screenOrientation=&quot;${screenOrientation}&quot; /&gt;</pre><p>Alternatively, you can specify in the form of key-value pairs at once by assigning manifestPlaceholders as array like this:</p><pre><em>// build.gradle</em><br>android {<br>  defaultConfig {<br>    manifestPlaceholders = [baseUrl: &quot;dev.demoserver.com&quot;,<br>                            screenOrientation: &quot;portrait&quot;,<br>                           ]<br>  }<br>}</pre><h3>Managing Multiple Manifests</h3><p>While managing separate Manifest files for each build variant sounds easy and straightforward, it can get cumbersome as the build variants and flavors grow in your Android app.</p><p>For example, your app module has multiple flavors which are needed for different build variants. The app.gradle file will look like this:</p><pre><em>// build.gradle</em><br>android {<br>  buildTypes {<br>    release { ... }<br>    debug { ... }<br>  }<br>  flavorDimensions &quot;ui&quot;, &quot;paidui&quot;, &quot;trialui&quot;, &quot;referralui&quot;<br>  productFlavors {<br>    paid {<br>      dimension &quot;ui&quot;<br>    }<br>    free {<br>      dimension &quot;paidui&quot;<br>    }<br>    trial {<br>      dimension &quot;trialui&quot;<br>    }<br>    referral {<br>      dimension &quot;referralui&quot;<br>    }<br>  }<br>}</pre><p>Here, ui and proui are flavor dimensions which are respectively assigned to flavors paid and free. This allows you to generate and assign separate source-set configuration for your app, including separate Manifest files. In a verbose manner, this would result in files generation as below:</p><ul><li>app/src/paidDebug/AndroidManifest.xml</li><li>app/src/paidRelease/AndroidManifest.xml</li><li>app/src/freeDebug/AndroidManifest.xml</li><li>app/src/freeRelease/AndroidManifest.xml</li><li>app/src/trialDebug/AndroidManifest.xml</li><li>app/src/trialRelease/AndroidManifest.xml</li><li>app/src/referralDebug/AndroidManifest.xml</li><li>app/src/referralRelease/AndroidManifest.xml</li></ul><p>While using multiple Manifest files sounds like an idea which is simple, it has its own problems:</p><ul><li>Management of multiple Manifest files get trickier with growing number of flavors</li><li>The code becomes error-prone since the complexity and number of iteration increases with each file and flavor</li><li>Updating any configuration in Manifest requires replication in all the remaining Manifest files which can get troublesome</li><li>File comparison, error identification, Manifest merging and differentiating files from each other becomes extremely difficult</li></ul><p>To solve this, you can inject variables into your AndroidManifest.xml file, which will make sure that you have to manage only one file for all your configurations and flavors specified in Gradle.</p><p>Once AndroidManifest.xml files are ready, Android toolchain makes use of <strong>Manifest merge</strong> policies to merge all the manifest files into a single source. Let us understand how the Android Manifest merging process works.</p><h3>Merging Multiple Manifests</h3><p>Android toolchain includes Manifest merging tool which matches elements between multiple Manifest files logically and takes necessary steps to generate a final merged Manifest file. This tool matches elements with two different approaches:</p><ul><li>Key element matching, e.g. “android:name&quot; declared inside &lt;action&gt; tag</li><li>XML tag matching, e.g. &lt;supports-screen&gt; tag</li></ul><p>Understanding the merging process becomes crucial since multiple files can introduce conflicts and errors. You can check the merged Manifest file preview in Android Studio by navigating to AndroidManifest.xml file and then <strong>Merged Manifest Viewer</strong> at the bottom of the editor.</p><p>The Merged Manifest view shows you the final resulting output of the merged Manifest files on the left whereas the information to specific details and sources on the right. Different priority is set to different Manifest files, which are denoted by different colors on the left as well as a color legend is also provided on the right.</p><p>When any two or more Manifest files include the same XML element, then the merging tool performs merging based on three predefined merge policies:</p><h4>Merge</h4><p>This is the standard strategy, which combines all non-conflicting elements and properties in the same tag. In the next step, child elements are merged according to their respective merge policy — if any elements or properties conflict with each other, then <a href="https://developer.android.com/studio/build/manage-manifests#merge_rule_markers">merge rule markers</a> are used to merge such elements or properties together.</p><h4>Merge Children Only</h4><p>In this policy, the merge tool gives precedence to the attributes and tags of parents elements to the highest priority manifest, while the child elements from all the Manifest files are merged according to the merge policy.</p><h4>Keep</h4><p>This policy applies to all the children which <strong>keeps</strong> all the elements as is and adds them to the parent element with the same declaration in the merged Manifest file. This is a relatively less used strategy as it only allows elements with multiple declarations being accepted for the same parent.</p><h4>Manifest Merge Conflicts and Resolution</h4><p>If conflict(s) appear while merging multiple Manifest files, they are displayed under the Merging <strong>Errors</strong> section on the right side of the editor. This section also helps you with hints or recommendations on how to resolve the conflict using the merge rules we discussed above.</p><p>For advanced level configuration and Manifest merging, it becomes critical to ensure that the correct elements are merged when the final merged result of AndroidManifest.xml is generated. To verify the same, you can find the log file which contains all the merging steps and decision tree performed by Android toolchain to merge multiple Manifest files for you.</p><p>You can find the log files under build/outputs/logs directory, where the file name appears something like manifest-merger-*buildvariant*-report.txt. This file gets updated every time Manifest is updated and Manifest merging takes place.</p><h3>Build Your Own Manifest</h3><p>You’ve gathered all the important pieces to understand how Android Manifest placeholders can be useful for your Android apps. Let’s look at one such example below:</p><h4>Support Multiple Deep Links</h4><pre>&lt;intent-filter&gt;<br>  &lt;action android:name=&quot;android.intent.action.VIEW&quot; /&gt;<br>  &lt;category android:name=&quot;android.intent.category.BROWSABLE&quot;/&gt;<br>  &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;<br>  <em>&lt;!-- custom intent filter definition for deep links --&gt;</em><br>  ${deepLinks_manifestPlaceholder}<br>&lt;/intent-filter&gt;</pre><p>Here, ${deepLinks_manifestPlaceholder} will be replaced with a specific deep link definition. This way, you can generate deep links to accept data and intent from multiple domains, subdomains and schemes in order to navigate your users to a specific screen as well as perform any actions on the basis of data provided via deeplink.</p><h4>Manage Your Sentry.io Configuration</h4><p>When setting up your Android app, Sentry will supply you with a DSN, or Data Source Name, a unique value. It seems like a standard URL, but it’s actually a representation of the Sentry SDKs’ configuration. The protocol, public key, server IP, and project identity are only a few of the components.</p><p>The default DSN configuration looks like this in the Manifest:</p><pre>&lt;application&gt;<br>  &lt;meta-data android:name=&quot;io.sentry.dsn&quot; android:value=&quot;https://1093t8yhqfw8h819@x11.ingest.sentry.io/123123&quot; /&gt;<br>  <em>&lt;!-- Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.<br>   We recommend adjusting this value in production. --&gt;</em><br>  &lt;meta-data android:name=&quot;io.sentry.traces.sample-rate&quot; android:value=&quot;1.0&quot; /&gt;<br>&lt;/application&gt;</pre><p>Here, it is important to note that, the meta-data value specified for io.sentry.traces.sample-rate specifies the performance monitoring scale for Sentry to capture the transactions. Value 1.0 equals 100% of transactions being captured. This can vary based on different environments, such as during development v/s in production.</p><p>Also, capturing transactions requires you to declare performance monitoring as well as Activity’s instrumentation. The Activity’s instrumentation is declared as below:</p><pre>&lt;meta-data android:name=&quot;io.sentry.traces.activity.enable&quot; android:value=&quot;true&quot; /&gt;<br>&lt;meta-data android:name=&quot;io.sentry.traces.activity.auto-finish.enable&quot; android:value=&quot;true&quot; /&gt;</pre><p>Here’s how you can replace it with Manifest placeholders to achieve seamless performance monitoring for multiple environments:</p><p>The build.gradle file would look like this:</p><pre>android {<br>  buildTypes {<br>    release { <br>      manifestPlaceholders.sentryTraceSampleRate = &quot;0.6&quot;<br>      manifestPlaceholders.sentryActivityTrace = true<br>      manifestPlaceholders.sentryAutoFinishActivityTrace = true<br>    }<br>    debug {<br>      manifestPlaceholders.sentryTraceSampleRate = &quot;1.0&quot;<br>      manifestPlaceholders.sentryActivityTrace = false<br>      manifestPlaceholders.sentryAutoFinishActivityTrace = false<br>    }<br>  }<br>}</pre><p>With the above build.gradle, you can modify your AndroidManifest.xml to support placeholders as below:</p><pre>// AndroidManifest.xml<br>&lt;application&gt;<br>  &lt;meta-data android:name=&quot;io.sentry.dsn&quot; android:value=&quot;https://1093t8yhqfw8h819@x11.ingest.sentry.io/123123&quot; /&gt;<br>  <em>&lt;!-- Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.<br>      We recommend adjusting this value in production. --&gt;</em><br>  &lt;meta-data android:name=&quot;io.sentry.traces.sample-rate&quot; android:value=&quot;${sentryTraceSampleRate}&quot; /&gt;<br>  &lt;meta-data android:name=&quot;io.sentry.traces.activity.enable&quot; android:value=&quot;${sentryActivityTrace}&quot; /&gt;<br>  &lt;meta-data android:name=&quot;io.sentry.traces.activity.auto-finish.enable&quot; android:value=&quot;${sentryAutoFinishActivityTrace}&quot; /&gt;<br>&lt;/application&gt;</pre><p>This way, you can also declare properties in your build.gradle and access them in AndroidManifest.xml with the help of manifest placeholders.</p><h3>Conclusion</h3><p>AndroidManifest.xml is an important part of any Android application, since it contains all the necessary configuration to run and navigate through your app as well as what kind of data, permissions and external dependencies are allowed.</p><p>In this article, you saw how you can customize elements in the Manifest file in order to provide variables so that different customizations can work well alongside each other, avoiding messy code as well as avoiding managing multiple Manifest files. This versatile approach not only speeds up your development time, but also gives you more control and power to manage your apps while entertaining a wide variety of customizations specific to build flavors and requirements.</p><p><a href="https://sentry.io/welcome/?utm_source=ProAndroidDev&amp;utm_medium=referral&amp;utm_campaign=android-manifest-sneh"><strong>Sentry</strong></a> is essential for monitoring application code health. From Error Tracking to Performance Monitoring, developers can see clearer, solve quicker, and learn continuously about their applications — from the frontend to the backend. Loved by over 1 million developers and more than <em>80,000 organizations worldwide</em>, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games.</p><p><em>Originally published at </em><a href="https://blog.sentry.io/2022/03/30/android-manifest-placeholders?utm_source=ProAndroidDev&amp;utm_medium=referral&amp;utm_campaign=android-manifest-sneh"><em>https://blog.sentry.io</em></a><em> on March 30, 2022.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=12f3743b920d" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/android-manifest-placeholders-12f3743b920d">Android Manifest Placeholders</a> was originally published in <a href="https://proandroiddev.com/">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dev team productivity tips: Managing multiple apps at scale]]></title>
            <link>https://medium.com/code-well/dev-team-productivity-tips-managing-multiple-apps-at-scale-61fbdacd3c18?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/61fbdacd3c18</guid>
            <category><![CDATA[development]]></category>
            <category><![CDATA[codemagic]]></category>
            <category><![CDATA[tips]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Fri, 11 Feb 2022 11:19:01 GMT</pubDate>
            <atom:updated>2022-02-11T11:19:01.439Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*G0129hTehpqvFa52.png" /></figure><p>Not all software development and delivery teams have embraced the DevOps approach to software development and delivery. But it’s striking how many have, and it’s even more striking how successful many adopters of DevOps have become. While some of the practices and technologies associated with DevOps are still immature, small teams have nevertheless evolved from basic agile development techniques to a more comprehensive engagement with their company’s overall IT capabilities. Businesses are seeing happier customers, and they’re beginning to see bottom-line results.</p><p>When DevOps efforts are successful, it’s not uncommon for the people who achieved that success to get inundated with requests for new projects, applications and infrastructure.</p><h3>Why do you need to configure your environment?</h3><p>Here are the reasons you should manage configuration and app settings variations per environment using deployment tools:</p><p><strong>More maintainable</strong>: These tools allow you to manage variables and secrets at multiple levels. For variables that are needed in many release definitions, you can store variables in a project. You can also define configuration variables that are scoped to a specific release definition or a specific environment in a release definition. Team Services provides an easy interface to manage these variables at each of these scopes.</p><p><strong>Fewer locations to update</strong>: By storing your configuration and app settings in a deployment tool, if settings change at a given time, you only need to update the settings in the deployment tool rather than in every possible file that the setting is hard-coded in. Furthermore, by storing them in the right scope, you do not have to update all the release definitions or environments in which they are used.</p><p><strong>Fewer mistakes</strong>: When storing the appropriate settings for each environment in the environment itself in the deployment tool, you won’t accidentally point to the development connection string when in production. The values for settings are siloed out per environment, so it would be hard to actively mix them up if using a deployment tool.</p><p><strong>Secure environment</strong>: When you have connection strings, passwords or any other settings stored in plaintext in a settings file, anyone who has access to the code can potentially access a database or machine. Restricted access roles and a rich permissions model for determining who can manage and use secrets at each scope are the way to go.</p><p><strong>Reliable automation</strong>: By automating the process of transforming configurations through a deployment tool, you’ll be able to count on the transforms always happening during deployment and setting the appropriate values.</p><p>Now, let’s look at the strategies that will help you manage multiple applications at scale.</p><h3>Determining if your application is scalable</h3><p>The best way to find out if your application is scalable before it gets deployed to thousands of users is to test it in various ways. The main idea of scalability testing is to determine the major workloads and mitigate bottlenecks that can impede your app’s scalability. To ensure you make the application truly scalable, it is vital to regularly and rigorously test it for scalability issues. Even if your customers want all the advantages of using your app, they’ll be disappointed by simple scalability and performance issues.</p><p>In load testing, you set criteria to ensure releases of a product meet certain conditions, like a given number of users they can support while delivering a specific response time. Performance testing is undertaken to analyze and improve your app’s performance. This type of test mainly focuses on optimizing resource consumption by analyzing data composed during testing.</p><p>Scalability testing caters to performance testing centered on a detailed understanding of the scalability of an application. The goal is to focus on the breaking point when the application stops scaling and to find the underlying issues.</p><h3>Scaling from the initial stage</h3><p>Planning to scale your apps before actually scaling them is an excellent business strategy. Design your apps in a way that allows them to grow to the point where they are being used by thousands or millions of people. Here are some important questions to ask yourself and your team before getting started:</p><ul><li>On average, how many people will use the app in the coming months?</li><li>What kind of data is involved? How do you plan to manage it?</li><li>What is the approximate time range required to fit all your customers on one server?</li><li>How will you manage more customers or data than expected?</li></ul><p>These initial phases of planning to scale involve both creating the technology needed to provide growth and informing business decisions. You need to take the past growth rate and expected growth rate into account and determine what potential technology limits will be encountered.</p><h3>Managing application architecture</h3><p>To get a better idea of why we need to move away from monoliths, let’s look at the example of NASA’s Apollo 13 mission. Apollo 13 was made of two ships: the lunar module and the command module. In software terms, these were essentially two giant monoliths.</p><p>When the command module experienced an oxygen failure, its crew needed to repurpose oxygen filters from the lunar module. However, the lunar module engineers designed their oxygen filters differently, causing a major headache when the crew needed to reassemble and retrofit these parts.</p><p>There are multiple approaches available for creating reliable infrastructure for maintaining multiple applications at scale:</p><h3>Microservices</h3><p>Microservices are an approach to developing a single application as a suite of small services instead of one single giant app. Each small service runs in its own process instead of relying on one single process to run the entire app. A typical example is an e-commerce app that is split into microservices: one for payment, one for the front-end user interface, one for email notifications, one for managing comments and another one for recommendations.</p><p>While much of the discussion about microservices has revolved around architectural definitions and characteristics, their value can be more easily understood through fairly simple business and organizational benefits.</p><ul><li>Code can be updated more easily, and new features or functionality can be added without changing the entire application.</li><li>Teams can use different stacks and different programming languages for different components.</li><li>Components can be scaled independently of one another, reducing the cost and complexity associated with having to scale entire applications.</li><li>Microservices compose a single application from many smaller, loosely coupled services, in contrast to the monolithic approach of a large, tightly coupled application.</li></ul><h3>Serverless computing</h3><p>Serverless computing is a cloud computing model that provisions computing resources on demand and offloads all responsibility for common infrastructure management tasks, e.g., scaling, scheduling, patching, provisioning, etc. The serverless model requires no management and operation of infrastructure, giving developers more time to optimize code and develop innovative new features and functionality.</p><p>There are most definitely servers in serverless computing. The term serverless persists because it describes the customer’s experience of servers: They’re essentially invisible because the customer doesn’t see them, manage them or interact with them in any way.</p><p>The most useful way to define and understand serverless is by focusing on the core attributes that distinguish serverless computing from other computing models, namely:</p><ul><li>The serverless model requires no management and operation of infrastructure, giving developers more time to optimize code and develop innovative new features and functionality.</li><li>Serverless computing runs code on demand only, typically in a stateless container on a per-request basis, and scales transparently with the number of requests being served.</li><li>Serverless computing enables end users to pay only for resources being used, never paying for idle capacity.</li><li>For certain workloads, such as those that require parallel processing, serverless computing can be both faster and more cost-effective than other forms of computing.</li></ul><h3>White label apps</h3><p>A white label app is an app developed by a white label platform or private label development organization and subsequently rebranded and re-sold by other organizations. This sort of method is utilized mainly for generic items and services that fall under the mass manufacturing category.</p><p>White label applications do not require any significant initial expenditure. This may be advantageous for many organizations, notably startups and smaller organizations whose budget does not enable them to commit to more substantial spending. The advantages of white label apps are:</p><ul><li><strong>Customization </strong>— the app can be heavily customized to reflect the brand’s image. This is useful when a customer wants to sync a product or service with its website and social media networks.</li><li><strong>Reduced marketing time </strong>— be it a regional organization or a global enterprise, once white label solutions are established in the market, they will simply be an added benefit for the organization’s clients.</li><li><strong>Single codebase </strong>— in most cases, the organization only needs to maintain one codebase, and all of the configuration is stored independently of the code that is written. The configuration is injected while the builds are made, and the specific flavor is ready in no time!</li></ul><h3>Managing infrastructure</h3><p>When an organization wants to expand its DevOps capability across more — and potentially larger — projects, the first step is to create a process and workflow that can be repeated by multiple teams. Another key to expanding DevOps is to ensure that the early initiative proves the benefits in terms of time savings, cost savings, business results, etc. As a broader effort gets underway, teams will have clearer expectations with these established measures for effectiveness.</p><p>Your continuous delivery pipeline typically consists of multiple environments. You may want to deploy changes to a test or staging environment first before deploying to a production environment. Furthermore, your production environment may itself comprise multiple scale units, each of which you may deploy in parallel or one after the other for a gradual rollout.</p><h3>Containers and orchestration</h3><p>There is quite a bit of complexity associated with using so many types of cloud computing simultaneously across an organization, and there is potential for these clouds to turn into a storm with data as well as applications in use across multiple cloud solutions.</p><p>Cloud orchestration is a process that can be used to manage these multiple workloads in an automated fashion across several cloud solutions, with the goal being to synthesize them into a single workflow. Similar to an orchestra, the goal is to get all the instruments to perform the same piece together. This makes cloud orchestration like the musical conductor that controls the performance and keeps it in sync. Popular examples include Kubernetes, Docker Swarm and Red Hat OpenShift.</p><p>Cloud orchestration involves the coordination of multiple tasks. There are often fewer manual coding requirements, as the coding from cloud automation is built upon, which prevents redundant work. Compared to cloud automation, cloud orchestration works on a higher level of coordination, as the processes are already streamlined through cloud automation.</p><h3>Infrastructure as Code</h3><p>Infrastructure as Code (IaC) uses a high-level descriptive language to automate the provisioning of IT infrastructure. This automation eliminates the need for developers to manually provision and manage servers, operating systems, database connections, storage and other infrastructure elements every time they want to develop, test or deploy a software application.</p><p>IaC is also an essential step in the DevOps lifecycle and is indispensable for competitively paced software delivery. It enables teams to rapidly create and version infrastructure in the same way they version source code and to track these versions so as to avoid inconsistency among IT environments, which can lead to serious issues during deployment.</p><h3>Managing delivery</h3><p><strong>Use a Container-Based Pipeline</strong>: If a pipeline is containerized, you can run it independently with different language versions. Shared libraries are not the solution, as they create version-specific conflicts and ultimately result in havoc. Using a Docker image is better than using shared libraries because users can self-serve images with whatever version they want. There are many resources on <a href="https://hub.docker.com/">Docker Hub</a> that make it easier to perform common CI/CD steps, such as building a Docker image, cloning a Git repository, running unit tests, linting projects and security scanning. Using these images can help reduce wasted development effort.</p><p><strong>Contextual Operation</strong>: Instead of managing thousands of pipelines for all your applications or microservices, use a minimal number of malleable pipelines for all integrations and deployments. This method involves Triggers, which carry information to direct actions. In this setup, Triggers carry context, or metadata, allowing a pipeline to change its behavior accordingly. These Triggers could be time based or centered around actions like a repo Git commit or pushing a new image. When a trigger is initiated, it brings in relevant dependencies to perform an action, such as cloning a repository or codebase. Further steps can then consume these unique criteria.</p><p><strong>Canary Testing</strong>: If an organization has tens of applications, hundreds of pipelines or thousands of microservices, spinning up each instance to run independent tests can quickly become cost-prohibitive. Testing early becomes less useful as infrastructure complexity arises. To solve this issue, teams can adopt a canary release strategy. Canary releasing is a practice in which new software is first released and tested among a small subgroup of users. It’s a good way to limit the blast radius of a change that goes wrong.</p><p><strong>Centralized Management</strong>: As multiple solutions for installation and lifecycle management sprang up, companies seeking to adopt solutions such as orchestration (e.g., Kubernetes) had to figure out the right approach. With the open-source community standardizing technologies like Cluster API for installation and declarative lifecycle management of multiple clusters, a new path toward consistency in this respect across clouds has emerged. There is a shift in how teams are building their environments and how they are moving away from deploying one large cluster for workloads that is subdivided using namespaces. Instead, they are adopting a more resilient architecture that enables the deployment of many workload clusters and an ephemeral, cluster-as-cattle mentality to proactively reduce their business risk.</p><p><strong>Group-Based Deployments</strong>: Organizations should also ensure they have group-based deployments to target specific users and enable administrators to target users with pre-defined bundles of applications that can be installed with a single click. This means leveraging content delivery networks (CDNs) that allow for cloud-based, on-demand bandwidth that is capable of pushing apps to large groups of users without clogging up network bandwidth.</p><h3>Business insights</h3><h3>DevOps pipelines: Codemagic</h3><p><a href="http://codemagic.io/">Codemagic</a> provides a versatile infrastructure for running and building pipelines for all mobile use cases. From encrypting sensitive information in environment variables to using codemagic.yaml for custom workflows, this feature-rich platform makes it possible for teams to ship mobile apps 50% faster.</p><p><a href="https://codemagic.io/pricing/">Codemagic’s business plan</a> offers concurrent builds, unlimited build minutes, in-app support and a pool of external third-party integrations to supercharge your workflows, as well as priority feature requests to address the special needs of your business use case.</p><h3>IBM Cloud Orchestrator</h3><p>Cloud orchestration is accomplished via a vendor, such as IBM Cloud Orchestrator — which supports public, private and hybrid clouds. Using such a platform promises benefits like reducing service delivery times by up to 90%. By fully automating previously manual workloads, common processes are implemented, and costs are reduced. Innovation is also hastened on public cloud services, while business policies are consistently imposed. Service-level agreements (SLAs) are also met.</p><p>IBM Cloud Orchestrator is a customizable self-service portal. It can automate many IT processes and works with multiple cloud providers, including Amazon EC2, Microsoft Azure and IBM’s SoftLayer. The higher-level Enterprise tier adds instant health dashboards, multi-tenant cloud usage reporting and what-if capacity analysis.</p><h3>Serverless and microservices: Microsoft Azure</h3><p>Azure Static Web Apps is a turnkey service for modern full-stack web apps with pre-built and pre-rendered static front ends and serverless API back ends. You can use it to develop with popular front-end frameworks or static site generators, quickly build and test your apps locally, and deploy with a simple check-in. This enables you to focus on developing your app while Azure takes care of the deployment and infrastructure.</p><h3>Conclusion</h3><p>Scalability is vital for your application’s success. When scalability is possible, it can enhance growth, offer a good user experience for new users and give you a better return on investment. If your target audience numbers in the thousands or millions, then proper planning and execution are required from the beginning. Additionally, ensure you have a suitable process in place to manage new servers as required.</p><p>Be ready for rising demand by having images of advanced virtual machines that are connected to run each of the servers. This way, they will be connected with the latest configuration and be functional with your infrastructure in a fraction of the time. In fact, any seasoned mobile app development company will always take care of scalability from day one. Do not wait until the app serves all its current users — instead, begin testing from the initial phase with loading tests, performance tests and scalability tests to achieve the best results.</p><h3>Useful links and resources</h3><ul><li>Here’s an article on <a href="https://blog.codemagic.io/maintaining-automated-build-pipelines/">how to maintain your automated build pipelines</a>.</li><li>Here’s an article on <a href="https://blog.codemagic.io/what-is-mobile-devops-and-why-should-you-care/">what Mobile DevOps is and why you should care</a>.</li><li>Here’s an article on <a href="https://blog.codemagic.io/devops-testing-tools/">DevOps testing tools in 2021</a>.</li><li>For discussions, learning and support, join the <a href="https://blog.codemagic.io/join-our-slack-community-for-continuous-integration/">Codemagic Slack Community</a>.</li></ul><p><a href="https://medium.com/u/7dc08545ed6d">Sneh Pandya</a> is a Senior Product Manager based in Baroda. He is a community organizer at Google Developers Group and co-host of NinjaTalks podcast. His passion for building meaningful products inspires him to write blogs, speak at conferences and mentor different talents. You can reach out to him over Twitter (<a href="https://twitter.com/snehpandya18">@SnehPandya18</a>).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=61fbdacd3c18" width="1" height="1" alt=""><hr><p><a href="https://medium.com/code-well/dev-team-productivity-tips-managing-multiple-apps-at-scale-61fbdacd3c18">Dev team productivity tips: Managing multiple apps at scale</a> was originally published in <a href="https://medium.com/code-well">Code Well Mobile</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 improve the performance of a React Native app]]></title>
            <link>https://medium.com/code-well/how-to-improve-the-performance-of-a-react-native-app-a7a98c9aca7b?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/a7a98c9aca7b</guid>
            <category><![CDATA[mobile-development]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[app-development]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Fri, 20 Aug 2021 02:02:51 GMT</pubDate>
            <atom:updated>2021-08-20T02:02:51.703Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*LBJqrDLFVBMXVTnk.png" /></figure><p>Good performance is crucial for any app or product. While working with React Native, you may often face problems with the performance of your app. That’s why you need to pay attention to the best practices and performance improvements for your React Native app during its development so that you can fix these issues and deliver a flawless experience to the end-users.</p><p>Let’s dive deep into the list of performance improvements and best practices you can utilize when developing your React Native apps!</p><h3>Provide Appropriate Navigation Strategies</h3><p>The React Native team has been working for quite some time on addressing problems related to navigation and have fixed plenty of them, but there are still some issues that need to be fixed for the majority of apps to provide a seamless experience.</p><p>Difficult navigation between screens can prevent users from using your app at all. React Native offers four different ways to build navigation:</p><ul><li><strong>iOS Navigator</strong>: Can be used only for iOS and won’t help in Android navigation development.</li><li><strong>Navigator</strong>: Can be used only for small applications and prototype development. Does not work well for complex or high-performance applications.</li><li><strong>Navigation Experiment</strong>: Can be used in complex applications, but due to the complexity of its implementation, not everyone likes it.</li><li><strong>React Navigation</strong>: Used by a large number of apps and often recommended. React Navigation is lightweight and can work for both small- and large-scale applications.</li></ul><h3>Avoid Use of ScrollView to Render Huge Lists</h3><p>There are a few ways to display items with scrollable lists in React Native. Two common ways to implement lists in React Native are through the use of the ScrollView and FlatList components.</p><p>ScrollView is simple to implement. It is often used to iterate over a list of a finite number of items, as shown below. However, it renders all children at once. This approach is good when the number of items in the list is quite low. On the other hand, using ScrollView with a large amount of data can directly affect the overall performance of the React Native app.</p><pre>&lt;ScrollView&gt;<br>  {items.map(item =&gt; {<br>    return &lt;Item key={item.name.toString()} /&gt;;<br>  })}<br>&lt;/ScrollView&gt;</pre><p>To handle large amounts of data in the list format, React Native provides FlatList. The items in FlatList are lazy loaded. Hence, the app does use an excessive or inconsistent amount of memory. FlatList can be used as shown below:</p><pre>&lt;FlatList<br>  data={elements}<br>  keyExtractor={item =&gt; `${items.name}`}<br>  renderItem={({ item }) =&gt; &lt;Item key={item.name.toString()} /&gt;}<br>/&gt;</pre><h3>Avoid Passing Inline Functions as Props</h3><p>When passing a function as a property to a component, avoid passing that function inline, like below:</p><pre>function MakeBeverage(props) {<br>  return(<br>    &lt;Button title=&#39; Make Beverage&#39; onPress={props.onPress}/&gt;<br>  <br>  )<br>}</pre><pre>export default function BeverageMaker() {<br> <br>  return (<br>    &lt;View style={styles.container}&gt;<br>      &lt;MakeBeverage<br>        onPress={()=&gt; console.log(&#39;making some beverage&#39;)}<br>      /&gt;<br>    &lt;/View&gt;<br>  );<br>}</pre><p>The above method isn’t recommended because any time the parent re-renders a new reference, the function is created again. This means that the child component re-renders even when the props didn’t change at all.</p><p>The solution is to declare the function as a class method or as a function inside a functional component so that the references remove any possibility of across re-renders.</p><pre>export default function BeverageMaker() {<br>  function handleMakeBeverage(){<br>    console.log(&#39;Making beverage, please wait!&#39;)<br>  }<br>  return (<br>    &lt;View style={styles.container}&gt;<br>      &lt;MakeBeverage<br>        onPress={handleMakeBeverage}<br>      /&gt;<br>    &lt;/View&gt;<br>  );<br>}</pre><h3>Scale and Resize Images</h3><p>It is important to optimize images to improve your React Native app’s performance if the app is built to showcase a huge amount of graphical content or images. Rendering multiple images could lead to high memory usage on a device if the images are not appropriately optimized in terms of resolution and size. This may cause your app to crash due to memory overload.</p><p>Some improvements that can be applied to optimize images in a React Native app are:</p><ul><li>Using PNG format instead of JPG format</li><li>Using smaller-resolution images</li><li>Using WEBP format for images — this can help reduce the images’ binary size on iOS and Android by nearly a third of the original size!</li></ul><h3>Cache Images</h3><p>React Native offers <a href="https://reactnative.dev/docs/image">Image</a> as a core component. This component is used to display an image, but it does not have an out-of-the-box solution for issues like:</p><ul><li>Rendering a huge number of images on a single screen</li><li>Low performance in general</li><li>Low performance in cache loading</li><li>Image flickering</li></ul><p>However, these issues can be easily resolved by using third-party libraries, like <a href="https://github.com/DylanVann/react-native-fast-image">react-native-fast-image</a>. This library is available for both iOS and Android, and it works like a charm!</p><h3>Avoid Updating state or dispatch Actions in componentWillUpdate</h3><p>You should make use of the componentWillUpdate lifecycle method to prepare for an update, not to trigger another one. If your aim is to set a state, you should do that using componentWillReceiveProps instead. To be on the safe side, use componentDidUpdate rather than componentWillReceiveProps to dispatch any Redux actions.</p><h3>Avoid Rendering Overhead and Unnecessary Renders</h3><p>React Native handles the rendering of components in a similar way to React.js. Therefore, the optimization techniques that are valid for React also apply to React Native apps. One optimization technique is to avoid unnecessary renders on the main thread. In functional components, this can be done by using React.memo().</p><p>React.memo() is used to handle memoization, meaning if any component receives the same set of properties more than once, it will use the previously cached properties and render the JSX view returned by the functional component only once, saving rendering overhead.</p><p>A good example of this is shown below, where the Animal component has a state variable called leg count that is updated with a number associated with each pair whenever the button is pressed. When the button is pressed, the WildAnimal component gets re-rendered, even though its text property does not change with each render. It is not doing anything special to its parent Animal component and is just displaying text. This can be optimized by wrapping the contents of the WildAnimal component with React.memo().</p><pre>// Animal.js<br>const Animal = () =&gt; {<br>  const [count, setCount] = useState(0);</pre><pre>  return (<br>    &lt;View style={{ flex: 1, justifyContent: &#39;center&#39;, alignItems: &#39;center&#39; }}&gt;<br>      &lt;Button title=&#39;Press me&#39; onPress={() =&gt; setCount(count + 2)} /&gt;<br>      &lt;WildAnimal text=&#39;text&#39; /&gt;<br>    &lt;/View&gt;<br>  );<br>};</pre><pre>// WildAnimals.js<br>const WildAnimal = React.Memo(({ text }) =&gt; {<br>  return &lt;Text&gt;{text}&lt;/Text&gt;;<br>});</pre><h3>Make Use of Hermes</h3><p><a href="https://reactnative.dev/docs/hermes">Hermes</a> is an open-source JavaScript engine optimized specifically for mobile applications. It is available for the Android platform for React Native version 0.60.4 and above. It is also available for iOS from version 0.64-rc.0 and above. Hermes helps reduce the download size of the APK, the memory footprint and consumption, and the time needed for the app to become interactive (TTI — Time to Interact).</p><p>To enable Hermes for Android, open build.gradle and add the following line:</p><pre>def enableHermes = project.ext.react.get(&quot;enableHermes&quot;, true);</pre><p>To enable Hermes for iOS, open Podfile and add the following line:</p><pre>use_react_native!(:path =&gt; config[:reactNativePath], :hermes_enabled =&gt; true</pre><h3>Use nativeDriver With the Animated Library</h3><p>One of the most popular ways to render animations in React Native apps is using the <a href="https://reactnative.dev/docs/animated.html">Animated</a> library.</p><p>It uses nativeDriver to send animations over the native bridge before the animation starts on the screen. This helps the animations to be executed independent of blocked JavaScript threads, thus resulting in a smoother and richer experience without flickering or dropping many frames. To use nativeDriver with Animated, you can set its value to true, as shown below:</p><pre>&lt;ScrollView<br>  showsVerticalScrollIndicator={ false }<br>  scrollEventThrottle={ 1 }<br>  onScroll={Animated.event(<br>    [{ nativeEvent: { contentOffset: { y: animatedValue } } }],<br>    { useNativeDriver: false }<br>  )}<br>&gt;<br>&lt;/ScrollView&gt;</pre><h3>Avoid Arrow Functions</h3><p>Arrow functions are a common culprit for wasteful re-renders. Don’t use arrow functions as callbacks in your functions to render views. With the arrow function, each render generates a new instance of that particular function, so when reconciliation happens, React Native compares a difference, and because the function reference doesn’t match, it is unable to reuse old references.</p><pre>class ArrowClass extends React.Component {<br>  // ...<br>  addTodo() {<br>    // ...<br>  }<br>  render() {<br>    return (<br>      &lt;View&gt;<br>        &lt;TouchableHighlight onPress={() =&gt; this.addTodo()} /&gt;<br>      &lt;/View&gt;<br>    );<br>  }<br>}</pre><pre>class CorrectClass extends React.Component {<br>  // ...<br>  addTodo = () =&gt; {<br>    // ...<br>  }<br>  render() {<br>    return (<br>      &lt;View&gt;<br>        &lt;TouchableHighlight onPress={this.addTodo} /&gt;<br>      &lt;/View&gt;<br>    );<br>  }<br>}</pre><h3>Avoid Excessive Use of Higher-Order Components</h3><p>When your application becomes complex and you want to share common patterns across your components, it is common to use higher-order components. Using higher-order components is, in fact, a good practice, even if it can sometimes be arguable, as it increases indirection. However, it can increase the complexity of your code.</p><p>What you should really be careful about is not instantiating a higher-order component on the fly, specifically during a render method. This is because this pattern effectively creates new components on its own.</p><p>React Native does not know (and does not identify) that this is effectively the same component as before. This puts lots of pressure on the reconciliation algorithms. More than that, it also forces React Native to run all the lifecycle methods.</p><h3>Avoid Implementing Bulk Reducers</h3><p>If you are not using Redux with normalizr and/or rematch or you are writing reducers yourself at some point, be careful to always mutate only the objects that you need to. When re-fetching a list of items from the network and saving it in the reducer, the naïve approach looks like this:</p><pre>function customReducer (state = {}, action) {<br>  switch (action.type) {<br>    case UPDATE_ITEMS_DOCS:<br>      return { ...state, ...action.docs }<br>    }<br>  }<br>  return state<br>}</pre><p>What you really need to do is update your store only when needed. More precisely, only update references that need to be updated. If an item already has the same value as before, then you don’t need to save a new reference for it in Redux. Updating references in your store will create useless renders that will produce the same components again and again.</p><h3>Move Views With Caution</h3><p>Moving views on the screen with scrolling, translating and rotating drops UI thread FPS. This is especially true when you have text with a transparent background positioned on top of an image or in any other situation where alpha composition is used to re-draw the views on each frame. You will find that enabling shouldRasterizeIOS or renderToHardwareTextureAndroid can help improve performance significantly.</p><p>Be careful not to overuse this, or your memory usage could get exponentially higher. Profile your performance and memory usage while using these properties. If you don’t plan to move any views anymore, turn this property off.</p><h3>Use Style References Correctly</h3><p>If you use objects or arrays for styling, they will create new instances with each new render. You should use a StyleSheet in React Native, which always passes a reference instead of a new object or array creation and allocation.</p><pre>class StylingClass extends React.PureComponent {<br>  render() {<br>    const style = {width: 10, height: 10}<br>    return (<br>      &lt;View style={{flex: 1}}&gt;<br>        &lt;View style={[style, {backgroundColor: &#39;red&#39;}]}/&gt;<br>      &lt;/View&gt;<br>    );<br>  }<br>}</pre><pre>import {StyleSheet} from &#39;react-native&#39;;</pre><pre>class CorrectClass extends React.PureComponent {<br>  render() {<br>    return (<br>      &lt;View style={style.container}/&gt;<br>    );<br>  }<br>}</pre><pre>StyleSheet.create({<br>  container: {<br>    flex: 1<br>  }<br>});</pre><h3>Make Use of InteractionManager</h3><p><a href="https://reactnative.dev/docs/interactionmanager">InteractionManager</a> allows you to schedule the execution of tasks on the JavaScript thread after any interactions or animations have been completed. In particular, InteractionManager allows JavaScript animations to run smoothly.</p><p>Tasks can be scheduled to run after interactions using the following code:</p><pre>InteractionManager.runAfterInteractions(() =&gt; {<br>  // ...long-running synchronous task...<br>});</pre><h3>Avoid Anonymous Functions While Rendering</h3><p>Creating functions in render() is a bad practice that can lead to some serious performance issues. Every time a component re-renders, a different callback is created. This might not be an issue for simple and smaller components, but it is a big issue for PureComponents and React.memo() or when the function is passed as a prop to a child component, which would result in unnecessary re-renders.</p><h3>Remove Console Statements</h3><p>Using console.log statements is one of the most common patterns to debug in JavaScript applications in general, including React Native apps. Leaving the console statements in the source code when publishing React Native apps can cause some big bottlenecks in the JavaScript thread.</p><p>One way to automatically keep track of console statements and remove them is to use a third-party dependency called babel-plugin-transform-remove-console. You can install the dependency by running the following command in a terminal window:</p><pre>npm install babel-plugin-transform-remove-console<br># OR<br>yarn add babel-plugin-transform-remove-console</pre><p>Once installed, modify the .babelrc file to remove the console statements, as shown below:</p><pre>{<br>  &quot;env&quot;: {<br>    &quot;production&quot;: {<br>      &quot;plugins&quot;: [&quot;transform-remove-console&quot;]<br>    }<br>  }<br>}</pre><h3>Enable the RAM Format</h3><p>Using the RAM format on iOS will create a single indexed file that React Native will load one module at a time. On Android, it will create a set of files for each module by default. You can force Android to create a single file, like iOS, but using multiple files can be more performant and requires less memory on Android.</p><p>Enable the RAM format in Xcode by editing the build phase “Bundle React Native code and images”. Before ../node_modules/react-native/scripts/react-native-xcode.sh add export BUNDLE_COMMAND=&quot;ram-bundle&quot;:</p><pre>export BUNDLE_COMMAND=&quot;ram-bundle&quot;<br>export NODE_BINARY=node<br>../node_modules/react-native/scripts/react-native-xcode.sh</pre><p>On Android, enable the RAM format by editing your android/app/build.gradle file. Before the line apply from: &quot;../../node_modules/react-native/react.gradle&quot;, add or amend the project.ext.react block:</p><pre>project.ext.react = [<br>  bundleCommand: &quot;ram-bundle&quot;,<br>]</pre><p>Use the following lines on Android if you want to use a single indexed file:</p><pre>project.ext.react = [<br>  bundleCommand: &quot;ram-bundle&quot;,<br>  extraPackagerArgs: [&quot;--indexed-ram-bundle&quot;]<br>]</pre><blockquote><em>Note: If you are using the Hermes JS Engine, you do not need RAM bundles. When loading the bytecode, mmap ensures that the entire file is not loaded.</em></blockquote><h3>Make Use of Memory Optimization</h3><p>Native applications have a lot of processes running in the background. You can find the unnecessary ones with the help of Xcode to improve performance. In Android Studio, there is an Android Device Monitor, which is used to monitor leaks in applications. Using scrolling lists like FlatListSectionList or isVirtualList is a sure way to increase performance.</p><p>You can use the following code to monitor performance and identify memory leaks:</p><pre>Import PerfMonitor from ‘react-native/libraries/Performance/RCTRenderingPerf’;<br>perfMonitor.toggle();<br>PerfMonitor.start();<br>SetTimeout ( () =&gt; {<br>perfMonitor.stop();<br>}; 2000);<br>}; 5000);</pre><h3>Make Use of Uncontrolled Inputs</h3><p>Contrary to best practices in React, where most of the input fields are controlled inputs, it is more performant to use uncontrolled inputs in React Native.</p><p>The problem with controlled inputs in React Native is that on slower devices or when a user is typing really fast, rendering glitches may occur while updating the view. Controlled inputs have to cross the RN-bridge because it deals with both the native and JavaScript thread.</p><p>Due to the known performance limitations of the RN-bridge, using uncontrolled inputs is the most accessible approach. This is as simple as removing the value property. Also, you don’t have to deal with re-renders because there are no state changes when the uncontrolled inputs are modified.</p><pre>export default function UncontrolledInputs() {<br>  const [text, onTextChange] = React.useState(&#39;Controlled inputs&#39;);<br> <br>  return (<br>    &lt;TextInput<br>      style={{  borderWidth: 1, height: 100, borderColor: &#39;blue&#39; }}<br>      onChangeText={text =&gt; onTextChange(text)}<br>      defaultValue={text}<br>    /&gt;<br>  );<br>}</pre><h3>Optimize Android App Size</h3><p>At the beginning of each React Native project, you usually don’t care about the application size. After all, it is hard to make such predictions so early in the process. But it takes only a few additional dependencies for the application to grow from the standard 5 MB to 10, 20 or even 50, depending on the codebase.</p><p>By default, a React Native application on Android consists of:</p><ol><li>Four sets of binaries compiled for different CPU architectures</li><li>A directory with resources, such as images, fonts, etc.</li><li>A JavaScript bundle with business logic and your React components</li><li>Other files</li></ol><p>Set the boolean flag enableProguardInReleaseBuilds to true, adjust the ProGuard rules to your needs and test release builds for crashes.</p><p>Also, set enableSeparateBuildPerCPUArchitecture to true.</p><p>You should also optimize the distribution process by taking advantage of <a href="https://developer.android.com/platform/technology/app-bundle/">Android App Bundles</a> when releasing a production version of your app.</p><h3>Debug Faster with Flipper</h3><p>Debugging is one of the most challenging tasks of every developer’s work. It is easier to introduce a new feature when everything seems to be working, but finding what went wrong can be very frustrating.</p><p>Time is an important factor in the debugging process, and we usually have to solve the issues quickly. However, debugging in React Native is not very straightforward, as the issue you are trying to solve can occur on different levels. Namely, it may be caused by:</p><ol><li>JavaScript: your application’s code or React Native, or</li><li>Native code: third-party libraries or React Native itself</li></ol><p><a href="https://fbflipper.com/">Flipper</a> is a debugging platform for mobile apps. It also has extensive support for React Native.</p><h3>Use Firebase Performance Monitoring</h3><p>Firebase Performance Monitoring is a service provided by Google that helps you to gain insights into the performance characteristics of your app. You should use the <a href="https://rnfirebase.io/perf/usage">Firebase Performance Monitoring SDK</a> for React Native to collect performance statistics and data from your apps, then review and analyze that data in the Firebase console.</p><h3>Conclusion</h3><p><a href="https://reactnative.dev/">React Native</a> is an open-source framework for creating cross-platform mobile applications. JavaScript is at its core, and it has components for building interfaces and functionalities. It is a popular high-performance framework that delivers a seamless experience at scale as long as you build apps with performance in mind from the start.</p><p>​<a href="https://medium.com/SnehPandya18">Sneh Pandya</a> is a Senior Product Manager based in Baroda. He is a community organizer at Google Developers Group and co-host of NinjaTalks podcast. His passion for building meaningful products inspires him to write blogs, speak at conferences and mentor different talents. You can reach out to him over Twitter (<a href="https://twitter.com/snehpandya18">@SnehPandya18</a>).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a7a98c9aca7b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/code-well/how-to-improve-the-performance-of-a-react-native-app-a7a98c9aca7b">How to improve the performance of a React Native app</a> was originally published in <a href="https://medium.com/code-well">Code Well Mobile</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Practical guide: React Native + Firebase + Codemagic (for iOS)]]></title>
            <link>https://medium.com/code-well/practical-guide-react-native-firebase-codemagic-for-ios-e807a9cb7dc?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/e807a9cb7dc</guid>
            <category><![CDATA[codemagic]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[cicd]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[firebase]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Thu, 19 Aug 2021 00:53:32 GMT</pubDate>
            <atom:updated>2021-08-19T00:53:32.251Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*3lds293xXtRYCZEd.png" /></figure><p>In this article, we will learn how to use Firebase for iOS in React Native projects and publish the app using CI/CD via <a href="https://codemagic.io/start">Codemagic</a>.</p><p><a href="http://console.firebase.google.com/">Firebase</a> is a popular cloud-hosted Backend-as-a-Service (BaaS) provided by Google to enrich the mobile and web development experience. Firebase allows developers to add a vast variety of services into their apps. Some of the most popular services are:</p><ul><li>User authentication</li><li>Cloud Storage</li><li>Deep links</li><li>Crashlytics</li><li>Test lab</li><li>Analytics</li><li>Web hosting</li></ul><p>Developers use Firebase services for various purposes. Firebase natively supports Android, iOS, web, Unity and even Google’s chatbot building service named Dialogflow.</p><p>Prerequisites</p><p>Before we start, we require the following:</p><ul><li>Access to the <a href="https://console.firebase.google.com/">Firebase Console</a> linked with a Google account</li><li>A React Native project in which Firebase services will be added</li><li>A completed <a href="https://reactnative.dev/docs/environment-setup">environment setup</a> for the React Native project focusing on iOS</li></ul><p>In this article, we will use the <a href="https://gitlab.com/snehpandya18/reactnativefirebaseapp">ReactNativeFirebaseApp</a> to set up Firebase services related to iOS in our React Native app. Similar setup steps can be followed for the Android version of the React Native app.</p><h3>Set up a new project on Firebase Console</h3><p>To get started with Firebase services, you need to have a Google account. Then follow the steps below to create a new project in the Firebase Console:</p><ul><li>Go to the <a href="https://console.firebase.google.com/">Firebase Console</a>, and log in with your Google account.</li><li>Click on the Add project button.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*aQiy8u5wpOO7LkSY.PNG" /></figure><ul><li>Enter a Project name of your choice, and click on Continue.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/690/0*ACi5KKgq966Br17m.PNG" /></figure><ul><li>We will set up Crashlytics for our React Native app for iOS in this article, so keep Google Analytics for this project enabled, and click Continue.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/644/0*7dDdFCtqvktDt8t-.PNG" /></figure><ul><li>Select your home country or the country where your organization is located. The country selection does not affect how Google processes and collects the data. Click on Create project.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/654/0*B2FNkDy9rsHuXgCJ.PNG" /></figure><ul><li>Let the project setup complete. Once done, you will see a completion status like below. Click on Continue.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/647/0*Dc05s31Wq27Hktqy.PNG" /></figure><p>You will be redirected to the Firebase project dashboard.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*38nc7Utg9PxDgRND.PNG" /></figure><h3>Set up a new React Native application</h3><p>Now, let’s add our iOS app configuration to the Firebase project. React Native creates directories for both Android and iOS, labeled as android and ios, respectively.</p><p>To complete the Firebase setup for iOS in React Native apps, you need to follow platform-specific steps. There are two ways to add Firebase to a React Native project:</p><ol><li>Using <a href="https://firebase.google.com/docs/reference/js">Firebase Web SDK</a></li><li>Using <a href="https://rnfirebase.io/">react-native-firebase</a></li></ol><p>To create a new application, run the commands below:</p><pre>npm install -g expo-cli // To add Expo CLI on your machine</pre><pre>npx react-native init ReactNativeFirebaseApp // To set up a new React Native app</pre><pre>cd ReactNativeFirebaseApp</pre><ul><li>On the Firebase Project Dashboard, click on the iOS icon.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/387/0*h-6T3uuUp0qMMOQK.PNG" /></figure><ul><li>You will be asked to fill in the details for your app, among which only bundle ID is mandatory for now. You can get the bundle ID of the iOS app from Xcode. Open the ios directory in Xcode, then click on the Runner section in the top-left corner. Copy the Bundle Identifier in the General tab of your main target.</li><li>If you prefer using the command line, you can execute the following command by providing the scheme and project workspace of the iOS app.</li></ul><pre>cd ios $ xcodebuild -workspace Runner.xcworkspace/ -scheme Runner -showBuildSettings | grep PRODUCT_BUNDLE_IDENTIFIER</pre><p>This will display the bundle identifier of the app. In our case, it’s com.snehpandya.rnfireapp. Enter the details in the Firebase Console, and click on Register app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/0*KCHM0UizhB8cZeIz.PNG" /></figure><ul><li>In the next step, download the GoogleService-Info.plist file provided by Firebase, and put it in the iOS app directory.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/802/0*dssx3R37zLqQwXqt.PNG" /></figure><ul><li>Open the ios folder of the project directory in Xcode by right-clicking and selecting Open in Xcode. Now, drag and drop the file that you downloaded into the Runner sub-folder. When a dialog box appears, make sure that Runner is selected in the Add to targets box. Then click Finish.</li><li>For an iOS app setup, Firebase walks you through a few more steps. However, you don’t have to perform them to set up your current app. So skip to the last step, and click Continue to console.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*h-RVLzx6b7E2vSE3.PNG" /></figure><ul><li>Once redirected, on the Firebase Console dashboard, you will see that the iOS version of your React Native app has been added to the Firebase.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/544/0*iHw4rMXsFEPVq2we.PNG" /></figure><ul><li>Click the gear icon beside Project Overview, then click Project Settings, and navigate to the General tab. Now, enter your email in the Support email field as shown in the image.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_nn_poJQVzBB-mtg.PNG" /></figure><h3>Add Crashlytics to your React Native app</h3><p>The Firebase SDK works as a bridge between Firebase services and the React Native app to access APIs. You can find a full list of available Firebase services and platform-specific documentation on the <a href="https://firebase.google.com/docs">Firebase Documentation page</a>.</p><p>To configure Firebase services in our React Native app:</p><ol><li>Open the ios/ folder in Xcode.</li><li>Right-click on the project, and then select Add files to …</li><li>Select the GoogleService-Info.plist file that we downloaded earlier, and make sure the Copy items if needed checkbox is enabled.</li><li>Open the Podfile, and add the FirebaseCrashlytics pod. Also, for an optimal experience, it is recommended to add the FirebaseAnalytics pod, as shown below:</li></ol><pre>pod &#39;Firebase/Crashlytics&#39;<br>pod &#39;Firebase/Analytics&#39;</pre><pre>pod install</pre><p>To access and use the Firebase SDK configuration on iOS, add the following into the /ios/ReactNativeFirebaseApp/AppDelegate.m file:</p><pre>import Firebase // Add to the top of the file</pre><pre>- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {<br>  // Add at the top of didFinishLaunchingWithOptions method<br>  FirebaseApp.configure()</pre><pre>  // ...<br>}</pre><ol><li>To initialize Crashlytics and automatically upload crash reports, go to Xcode, and navigate to the project file on the left pane.</li><li>From the Select a project or target dropdown, select your build target.</li><li>Select the Build Phases tab, then click + &gt; New Run Script Phase.</li><li>In the Run Script section, add a new script as shown below:</li></ol><pre>&quot;${PODS_ROOT}/FirebaseCrashlytics/run&quot;</pre><p>Add the app’s dSYM location as an input file, as shown below, to enable crash log reporting:</p><pre>${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}</pre><p>Finally, go to the ios project root directory, and run your project to verify and complete the initialization.</p><pre>cd ios/<br>pod install --repo-update<br>cd ..<br>npx react-native run-ios</pre><h3>Set up Firebase for Codemagic</h3><p><a href="https://codemagic.io/">Codemagic</a> is a versatile CI/CD solution for all types of mobile apps, including React Native. You can easily set up your React Native apps with minimal steps on the platform to automate your continuous integration and continuous delivery pipelines. If you are new to Codemagic, you can read the <a href="https://blog.codemagic.io/getting-started-with-codemagic/">Getting Started guide</a>.</p><p>Currently, our app is configured with Firebase Crashlytics. We will now configure our React Native project on Codemagic. Before we proceed, it is crucial to keep the privacy and security of our confidential keys intact.</p><p>While setting up Firebase for our project, we downloaded the GoogleService-Info.plist file and kept it in the local ios directory. This file includes sensitive configuration data and API keys for Firebase to verify and communicate with our app. For this reason, it should not be exposed, and hence, we will exclude it from our version control system like Git.</p><p>In the root directory of our project, open the .gitignore file, and add the exclusion as shown below. This will prevent the file from being tracked or committed by the version control system.</p><pre>ios/ReactNativeFirebaseApp/GoogleService-Info.plist</pre><p>After successfully excluding the configuration file, we still need the credentials for successful build generation on Codemagic. In order to provide them, we will upload an encrypted version of the file on Codemagic, which will be securely decrypted during build generation. The credentials will be wiped from Codemagic machines after the build is complete.</p><p>Follow the steps below to provide the encrypted version of the file:</p><ol><li>Navigate to your project on the Codemagic dashboard.</li><li>Choose the React Native build type for your app.</li><li>You will be shown the build configuration page, as shown below. Click on Encrypt environment variables at the bottom of the page.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/802/0*hlzGbnUXZ18s-hh0.PNG" /></figure><p>Drag and drop or upload the GoogleService-Info.plist file in the dialog. It will now generate an encrypted version of your file. Copy the encrypted string.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/561/0*b-0w5I7Ug271Wyi-.PNG" /></figure><ul><li>Download the codemagic.yaml file in the root directory of your project, and edit the XCODE_WORKSPACE and XCODE_SCHEME variables to provide appropriate values to each of them.</li><li>Add the copied encrypted string as shown below under the scripts block in the codemagic.yaml file:</li></ul><pre>echo $FIREBASE_IOS | base64 --decode &gt; $FCI_BUILD_DIR/ios/Runner/GoogleService-Info.plist</pre><p>This script will decode the base64 string to make use of the configuration and API keys during the build.</p><p>Commit the codemagic.yaml file to the version control system. Then click on Check for configuration file. Now, click on Start new build to build the app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/792/0*yxd0WpjN8Nlr90Hp.PNG" /></figure><p>We have successfully completed the setup and configuration of our React Native app for iOS with Firebase on Codemagic CI/CD.</p><h3>Conclusion</h3><p>With the popularity of React Native combined with Firebase’s services, your apps can be supercharged! Codemagic plays a key role, providing versatility and support for building, deploying and publishing apps for your end-users.</p><h3>Useful links and references</h3><ul><li><a href="https://blog.codemagic.io/react-native-firebase-codemagic-for-android/">Here’s a practical guide</a> on React Native + Firebase + Codemagic for Android.</li><li>React Native Firebase modules can be found <a href="https://github.com/invertase/react-native-firebase">here</a> and <a href="https://rnfirebase.io/">here</a>.</li><li>Practical guides on Firebase with Flutter for iOS and Android on Codemagic can be found <a href="https://blog.codemagic.io/practical-guide-flutter-firebase-codemagic/">here</a> and <a href="https://blog.codemagic.io/practical-guide-flutter-firebase-codemagic-on-android/">here</a>, respectively.</li><li>Learn how to load Firebase config in Codemagic with environment variables <a href="https://blog.codemagic.io/how-to-load-firebase-config-in-codemagic-with-environment-variables/">here</a>.</li><li><a href="https://blog.codemagic.io/react-native-getting-started-guide-with-codemagic/">Here’s a guide</a> on Continuous Integration and Delivery for React Native apps.</li><li><a href="https://blog.codemagic.io/develop-ios-apps-without-mac-with-react-native-codemagic/">Here’s a guide</a> on how to develop and distribute iOS apps without Mac with React Native and Codemagic.</li><li>A guide on app distribution using the Gradle plugin in Codemagic can be found <a href="https://blog.codemagic.io/firebase-app-distribution-with-codemagic/">here</a>.</li><li>A guide on Firebase app distribution using CLI can be found <a href="https://blog.codemagic.io/firebase-app-distribution-using-cli/">here</a>.</li></ul><p><a href="https://medium.com/u/7dc08545ed6d">Sneh Pandya</a> is a Senior Product Manager based in Baroda. He is a community organizer at Google Developers Group and co-host of NinjaTalks podcast. His passion for building meaningful products inspires him to write blogs, speak at conferences and mentor different talents. You can reach out to him over Twitter (<a href="https://twitter.com/snehpandya18">@SnehPandya18</a>).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e807a9cb7dc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/code-well/practical-guide-react-native-firebase-codemagic-for-ios-e807a9cb7dc">Practical guide: React Native + Firebase + Codemagic (for iOS)</a> was originally published in <a href="https://medium.com/code-well">Code Well Mobile</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Appium mobile testing — test React Native apps]]></title>
            <link>https://medium.com/code-well/appium-mobile-testing-test-react-native-apps-4a8fe7f916f5?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/4a8fe7f916f5</guid>
            <category><![CDATA[appium]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[mobile-testing]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[testing]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Wed, 18 Aug 2021 19:47:37 GMT</pubDate>
            <atom:updated>2021-08-18T19:47:37.544Z</atom:updated>
            <content:encoded><![CDATA[<h3>Appium mobile testing — test React Native apps</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5P9y1Wids0eklVE6.png" /></figure><p>React Native provides a cross-platform mobile app development experience without sacrificing the user experience or perceived performance. Developers love to build apps with a single codebase and methodology. <a href="https://appium.io/">Appium</a> is an open-source testing automation framework for cross-platform applications and mobile applications. When it comes to UI testing, Appium is a great option for testing React Native apps. React Native apps are testable out of the box with Appium — perfect for mobile testing.</p><p>Let’s learn how Appium can be used for React Native testing.</p><h3>Set up a new project</h3><p>To begin, create a new project for React Native using the command below:</p><pre>react-native init ReactNativeAppiumTest</pre><p>Now, install Appium through npm or as a standalone app.</p><pre>npm install -g appium</pre><p>The standalone version can be <a href="https://github.com/appium/appium-desktop/releases/">downloaded from here</a>.</p><p>Next, create a separate directory to write test cases. Ideally, it should be inside the project’s root folder to keep everything in place. Inside the tests folder, create a package.json file.</p><p><a href="https://webdriver.io/">WebdriverIO</a> is an open-source testing utility for NodeJS that supports Appium.</p><p>To install WebdriverIO, run the command below:</p><pre>npm install --save webdriverio @wdio/cli</pre><p>Next, install <a href="https://www.chaijs.com/">ChaiJS</a> as shown below to include support for assertion statements while writing test cases:</p><pre>npm install --save chai</pre><h3>Configure WebdriverIO</h3><p>The web driver config file needs to be generated to apply the configuration while testing. Run the command below inside the project:</p><pre>npx wdio config</pre><p>In return, the command prompt will ask a series of questions and install the required dependencies based on the input selections.</p><blockquote><em>Note: You need to select both the Mocha and Appium services when configuring via the command line.</em></blockquote><p>Once this is done, the wdio.conf file will be generated inside the tests directory.</p><p>Perform the following changes to configure WebdriverIO to work with Appium and run tests on Android Emulator:</p><pre>exports.config = {<br>  services: [&#39;appium&#39;],<br>  port: 4723,<br>  runner: &#39;local&#39;,<br>  specs: [<br>    &#39;./tests/specs/**/*.js&#39;<br>  ],<br>  capabilities: [{<br>     maxInstances: 1,<br>     browserName: &#39;&#39;,<br>     appiumVersion: &#39;1.13.0&#39;,<br>     platformName: &#39;Android&#39;,<br>     platformVersion: &#39;&lt;emulator platform version&gt;&#39;,<br>     deviceName: &#39;&lt;emulator name&gt;&#39;,<br>     app: &#39;&lt;path to APK&gt;&#39;,<br>     automationName: &#39;UiAutomator2&#39;<br>  }],<br>  <br>  logLevel: &#39;trace&#39;,<br>  bail: 0,<br>  waitforTimeout: 10000,<br>  connectionRetryTimeout: 90000,<br>  connectionRetryCount: 3,<br>  framework: &#39;mocha&#39;,<br>  reporters: [&#39;spec&#39;],<br>  mochaOpts: {<br>    ui: &#39;bdd&#39;<br>    timeout: 60000<br>  }<br>}</pre><p>In this file, Appium is added to the service list, and the default port for communication is also set. Declare the APK path, Android emulator name and version to complete the configuration. Also, maxInstances is set to 1 to avoid running multiple tests in parallel.</p><h3>Preparing demo application</h3><p>Let’s prepare a simple application for the purpose of React Native testing using Appium. In our case, we will add a simple login page to run tests using Appium. Inside the App.js file, add the code below:</p><pre>import React, { Component } from &#39;react&#39;;<br>import { TouchableHighlight, StyleSheet, Text, TextInput, View } from &#39;react-native&#39;;</pre><pre>export default class App extends Component {<br>  constructor() {<br>    super()<br>    this.state = {<br>      username: &#39;&#39;,<br>      password: &#39;&#39;,<br>      isLogined: false<br>    }<br>  }</pre><pre>  inputChangeHandler = (value, name) =&gt; {<br>    this.setState({<br>      [name]: value<br>    })<br>  }</pre><pre>  login = () =&gt; {<br>    if ((this.state.username == &#39;codemagic&#39;) &amp;&amp; (this.state.password == &#39;nevercode&#39;)) {<br>      this.setState({ isLogined: true });<br>    }<br>    else {<br>      this.setState({ isLogined: false });<br>    }<br>  }</pre><pre>  render() {<br>    return (<br>      &lt;View style={LOCAL_STYLES.wrapper} testID=&quot;app-root&quot; accessibilityLabel=&quot;app-root&quot;&gt;<br>        &lt;View style={LOCAL_STYLES.inputContainer}&gt;<br>          &lt;TextInput name=&quot;username&quot; accessibilityLabel=&quot;username&quot; style={LOCAL_STYLES.input} onChangeText={(text) =&gt; this.inputChangeHandler(text, &quot;username&quot;)} /&gt;<br>        &lt;/View&gt;</pre><pre>        &lt;View style={LOCAL_STYLES.inputContainer}&gt;<br>          &lt;TextInput name=&quot;password&quot; accessibilityLabel=&quot;password&quot; secureTextEntry={true} style={LOCAL_STYLES.input} onChangeText={(text) =&gt; this.inputChangeHandler(text, &quot;password&quot;)} /&gt;<br>        &lt;/View&gt;</pre><pre>        &lt;Text accessibilityLabel=&quot;loginstatus&quot;&gt;{this.state.isLogined ? &quot;success&quot; : &quot;fail&quot;}&lt;/Text&gt;</pre><pre>        &lt;TouchableHighlight style={LOCAL_STYLES.buttonContainer} accessibilityLabel=&quot;login&quot; onPress={this.login}&gt;<br>          &lt;Text style={{ color: &#39;white&#39; }}&gt;Login&lt;/Text&gt;<br>        &lt;/TouchableHighlight&gt;<br>      &lt;/View&gt;<br>    );<br>  }<br>}</pre><pre>const LOCAL_STYLES = StyleSheet.create({<br>  wrapper: {<br>    flex: 1,<br>    alignItems: &quot;center&quot;,<br>    justifyContent: &quot;center&quot;<br>  },</pre><pre>  inputContainer: {<br>    borderBottomColor: &#39;#AFAFAF&#39;,<br>    backgroundColor: &#39;#FFFFFF&#39;,<br>    borderRadius: 10,<br>    borderBottomWidth: 1,<br>    marginBottom: 16,<br>    flexDirection: &#39;row&#39;,<br>    alignItems: &#39;center&#39;,<br>    width: &#39;80%&#39;,<br>    borderColor: &#39;blue&#39;,<br>    borderWidth: 1<br>  },<br>  buttonContainer: {<br>    height: 45,<br>    width: 250,<br>    flexDirection: &#39;row&#39;,<br>    justifyContent: &#39;center&#39;,<br>    alignItems: &#39;center&#39;,<br>    marginBottom: 20,<br>    borderRadius: 20,<br>    backgroundColor: &quot;#00b5ec&quot;<br>  }<br>});</pre><p>To make the components testable, add a property to the relevant components. For Android, add accessibilityLabel, and for iOS, add testID, as shown in the code above.</p><p>Now run the app and check the screen. A simple login screen should open up. Next, let’s write test cases using Appium to verify our login functionality.</p><h3>Preparing the test case</h3><p>Inside the tests directory, create a new file named App.test.js, and add the code below:</p><pre>var expect = require(&#39;chai&#39;).expect;</pre><pre>describe(&#39;Simple App testing&#39;, () =&gt; {</pre><pre>  beforeEach(() =&gt; {<br>    $(&quot;~app-root&quot;).waitForDisplayed(10000, false)<br>  });</pre><pre>  it(&#39;Login test: valid case&#39;, async =&gt; {<br>    $(&#39;~username&#39;).setValue(&quot;codemagic&quot;);<br>    $(&#39;~password&#39;).setValue(&quot;nevercode&quot;);</pre><pre>    $(&quot;~login&quot;).click();</pre><pre>    $(&quot;~loginstatus&quot;).waitForDisplayed(11000);<br>    const status = $(&quot;~loginstatus&quot;).getText();<br>    expect(status).to.equal(&#39;success&#39;);<br>  });</pre><pre>  it(&#39;Login test: invalid case&#39;, async =&gt; {<br>    $(&#39;~username&#39;).setValue(&quot;nevercode&quot;);<br>    $(&#39;~password&#39;).setValue(&quot;codemagic&quot;);</pre><pre>    $(&quot;~login&quot;).click();</pre><pre>    $(&quot;~loginstatus&quot;).waitForDisplayed(11000);<br>    const status = $(&quot;~loginstatus&quot;).getText();<br>    expect(status).to.equal(&#39;fail&#39;);<br>  });<br>});</pre><p>The above test case will verify the login functionality and check whether the test passes or fails based on the input credentials. beforeEach is added to make sure the app is load prior to the test being run.</p><h3>Execute tests</h3><p>To execute the test case written above, let’s launch an emulator with the command below:</p><pre>react-native run-android</pre><p>Now, let’s start the Appium server in a separate command prompt to set up communication:</p><pre>appium</pre><p>In a new command prompt, run the webdriver test suite using the command below:</p><pre>npx wdio ./wdio.conf.js</pre><p>Once set up, the test execution will start, and the command prompt will show the logs of the executed steps in parallel when the emulator shows the test running.</p><p>Once the automation process is complete, you will see the test results as follows:</p><pre>App testing<br>    ✓ Login test: valid case<br>    ✓ Login test: invalid case</pre><pre>2 tests passing (10.1s)</pre><h3>Conclusion</h3><p>It is popular in the developer ecosystem to use Appium to test React Native apps. Appium makes it seamless to write test cases for both Android and iOS platforms while working with React Native. Selenium, the underlying web driver, works as a bridge between Appium and mobile platforms to deploy and execute tests.</p><h3>Assure the quality of your app with automated tests for React Native</h3><p><a href="https://reactnativeci.com/">Codemagic</a> mobile CI/CD makes it easy to automate the testing of your React Native apps. You can choose to run tests on the emulator or simulator or on real devices. Set up automatic build triggering to test every new commit.</p><p>Assure the quality of your React Native apps with automated tests. Run unit tests with <a href="https://blog.codemagic.io/testing-react-native-apps-with-jest/">Jest</a> or test the full app on the simulator/emulator or real devices with Appium or <a href="https://blog.codemagic.io/react-native-detox-tests-on-codemagic/">Detox</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*v0oXkYvReysMdL6c.png" /></figure><p>For testing your mobile apps on real devices you can use AWS Device Farm, Firebase Test Lab, BrowserStack and Sauce Labs.</p><h3>Useful links and resources</h3><ul><li>Here’s an article on <a href="https://blog.codemagic.io/why-android-developers-should-pay-attention-to-react-native-in-2021/">why Android developers should pay attention to React Native in 2021</a>.</li><li>Here’s an article on running <a href="https://blog.codemagic.io/react-native-detox-tests-on-codemagic/">React Native Detox tests on Codemagic</a>.</li><li>Here’s an article on <a href="https://blog.codemagic.io/testing-react-native-apps-with-jest/">React Native testing with Jest and Codemagic</a>.</li><li>Here’s an article on <a href="https://blog.codemagic.io/choosing-the-right-database-for-react-native-app/">choosing the right database for your React Native app</a>.</li><li>Here’s an article on <a href="https://blog.codemagic.io/improve-react-native-app-performance/">how to improve the performance of a React Native app</a>.</li><li>Learn about the options how to use <a href="https://blog.codemagic.io/continuous-integration-for-testing-mobile-apps/">CI/CD tool for testing mobile apps</a></li><li>Here’s a practical guide on <a href="https://blog.codemagic.io/react-native-getting-started-guide-with-codemagic/">Continuous Integration and Delivery for React Native apps</a>.</li><li>For discussions, learning and support, join the <a href="https://blog.codemagic.io/join-our-slack-community-for-continuous-integration/">Codemagic Slack community</a>.</li></ul><p><a href="https://medium.com/u/7dc08545ed6d">Sneh Pandya</a> is a Senior Product Manager based in Baroda. He is a community organizer at Google Developers Group and co-host of NinjaTalks podcast. His passion for building meaningful products inspires him to write blogs, speak at conferences and mentor different talents. You can reach out to him over Twitter (<a href="https://twitter.com/snehpandya18">@SnehPandya18</a>).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4a8fe7f916f5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/code-well/appium-mobile-testing-test-react-native-apps-4a8fe7f916f5">Appium mobile testing — test React Native apps</a> was originally published in <a href="https://medium.com/code-well">Code Well Mobile</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Testing React Native apps with Linux instances on Codemagic]]></title>
            <link>https://medium.com/code-well/testing-react-native-apps-with-linux-instances-on-codemagic-814aec5bebe7?source=rss-7dc08545ed6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/814aec5bebe7</guid>
            <category><![CDATA[codemagic]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[linux]]></category>
            <dc:creator><![CDATA[Sneh Pandya]]></dc:creator>
            <pubDate>Tue, 17 Aug 2021 01:02:35 GMT</pubDate>
            <atom:updated>2021-08-17T01:02:35.361Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*XJPuxSTHY-hUb7fU.png" /></figure><p>Did you know that <a href="http://codemagic.io/">Codemagic</a> now supports Linux instances too? Here’s yet another way to build and test React Native apps!</p><p>On Linux, you can build Android and other non-Mac workflows more quickly with out-of-the-box support for Android emulators with hardware acceleration. You can specify a Linux build machine by using linux or linux_x2 as instance type in codemagic.yaml.</p><p>Linux can only be used in codemagic.yaml configured workflows, so see the <a href="https://docs.codemagic.io/getting-started/yaml/">getting started guide</a> or <a href="https://blog.codemagic.io/codemagic-yaml-cheatsheet/">YAML cheat-sheet</a> to migrate over any workflows you want to use on Linux.</p><p>Let’s look at how to build and test React Native apps on Linux instances.</p><h3>Configure React Native Project</h3><p>For our setup, we will install the Jest testing framework:</p><pre>npm i jest --save-dev<br>npm install @testing-library/react-native --save-dev<br>npm install @react-navigation/native --save-dev</pre><p>Add the details in the package.json, as shown below:</p><pre>&quot;scripts&quot;: {<br>  &quot;test&quot;: &quot;jest&quot;<br>},<br>&quot;jest&quot;: {<br>  &quot;preset&quot;: &quot;jest-expo&quot;,<br>  &quot;setupFiles&quot;: [&quot;&lt;rootDir&gt;/testing/jest-setup.js&quot;]<br>}</pre><p>Let’s prepare a simple app that has two screens. Your app would look something like this:</p><pre>import React from &#39;react&#39;;<br>import { StatusBar } from &#39;expo-status-bar&#39;;<br>import { StyleSheet, Text, View, Button } from &#39;react-native&#39;;<br>import { NavigationContainer } from &#39;@react-navigation/native&#39;;<br>import { createStackNavigator } from &#39;@react-navigation/stack&#39;;</pre><pre>export const HomeScreen = ({ navigation }) =&gt; (<br>  &lt;View style={styles.container}&gt;<br>    &lt;Text&gt;Home Screen&lt;/Text&gt;<br>  &lt;Button title=&quot;Navigate to Detail Screen&quot; onPress={() =&gt; navigation.push(&#39;DetailScreen&#39;)} /&gt;<br>    &lt;StatusBar style=&quot;auto&quot; /&gt;<br>  &lt;/View&gt;<br>);</pre><pre>export const DetailScreen = () =&gt; (<br>  &lt;View style={styles.container}&gt;<br>    &lt;Text&gt;Detail screen&lt;/Text&gt;<br>    &lt;StatusBar style=&quot;auto&quot; /&gt;<br>  &lt;/View&gt;<br>);</pre><pre>const Stack = createStackNavigator();<br>export const AppStack = () =&gt; (<br>  &lt;Stack.Navigator&gt;<br>    &lt;Stack.Screen name=&quot;HomeScreen&quot; component={HomeScreen} /&gt;<br>    &lt;Stack.Screen name=&quot;DetailScreen&quot; component={DetailScreen} /&gt;<br>  &lt;/Stack.Navigator&gt;<br>);</pre><h3>Writing Tests for React Native</h3><p>Scenario 1: The Home Screen is the initial screen of the app, which has navigation enabled. The user is able to navigate to the Detail Screen by tapping on the button.</p><pre>import React from &#39;react&#39;;<br>import { render, fireEvent, waitFor } from &#39;@testing-library/react-native&#39;;<br>import { NavigationContainer } from &#39;@react-navigation/native&#39;;</pre><pre>import App, { HomeScreen, AppStack } from &#39;./App&#39;;</pre><pre>describe(&#39;HomeScreen’, () =&gt; {<br>  it(&#39;navigates on button press&#39;, () =&gt; {<br>    const push = jest.fn();<br>    const { getByText } = render(&lt;HomeScreen navigation={{ push }} /&gt;);<br>    fireEvent.press(getByText(&#39;Go to Detail Screen&#39;));<br>    expect(push).toHaveBeenCalledWith(‘Detail Screen&#39;);<br>  });<br>});</pre><p>Scenario 2: Let’s say you want to check your Detail Screen for a text box that collects users’ emails for a newsletter. Jest will test the selected component in JSON format.</p><pre>import &#39;react-native&#39;;<br>import React from &#39;react&#39;;<br>import renderer from &#39;react-test-renderer&#39;;</pre><pre>let findTextElement = function(tree, element){<br>    console.warn(tree)<br>    return true;<br>}</pre><pre>it(&#39;Find text element&#39;, ()=&gt;{<br>   let tree = renderer.create(<br>       &lt;Home /&gt;<br>   ).toJSON();</pre><pre>   expect(findTextElement(tree, &#39;email&#39;)).toBeDefined();<br>})</pre><h3>Running Tests for React Native</h3><p>We will now create a testing setup file called testing/jest-setup.js:</p><pre>import &#39;react-native-gesture-handler/jestSetup&#39;;</pre><pre>jest.mock(&#39;react-native/Libraries/Animated/src/NativeAnimatedHelper&#39;);</pre><pre>jest.mock(&#39;react-native-reanimated&#39;, () =&gt; {<br>  const Reanimated = require(&#39;react-native-reanimated/mock&#39;);<br>  Reanimated.default.call = () =&gt; {};<br>  return Reanimated;<br>});</pre><p>Testing on a local machine is simple — just go to your terminal and simply run npm test. This will run the tests you just implemented. You should be able to see an output similar to this:</p><pre>PASS  ./App.test.js</pre><pre>Home Screen<br>  ✓ navigates on button press (40ms)</pre><pre>AppStack<br>  ✓ renders the correct screen (32ms)</pre><pre>Detail Screen<br>  ✓ email field found (94ms)<br></pre><pre>Test Suites: 1 passed, 1 total<br>Tests:       2 passed, 2 total<br>Snapshots:   0 total<br>Time:        1.62s, estimated 2s<br>Ran all test suites related to changed files.</pre><h3>Running Tests on Codemagic</h3><p>Codemagic is a popular CI/CD solution that offers automated build pipelines to check continuous integration and run tests. To set up your React Native app on Codemagic, you can <a href="https://blog.codemagic.io/react-native-getting-started-guide-with-codemagic/">follow the steps provided here</a>.</p><p>This time, we will build and test our React Native app on a newly available Linux instance. Let’s set up a codemagic.yaml file to perform this.</p><pre>workflows:<br>  my-workflow:<br>    name: My workflow name<br>      instance_type: linux                # specify linux or linux_2 for Linux instances<br>      max_build_duration: 60<br>  ...</pre><pre>    scripts:<br>      - name: Install npm dependencies<br>        script: npm install<br>        <br>        ...</pre><pre>      - name: Tests                          # Insert before the build command<br>        script: npm test</pre><pre>        ...</pre><pre>      - name: Build Android app<br>        script: cd android &amp;&amp; ./gradlew assembleRelease<br>    <br>  ...</pre><p>Once codemagic.yaml is updated, you are ready to run your tests and build on Codemagic.</p><p>Codemagic can be configured to start the build process automatically after a commit or a pull request using <a href="https://docs.codemagic.io/flutter/automatic-build-triggering/">build triggers</a>. For now, we will trigger the build manually to start the tests and build process.</p><p>Just click on the “Start new build” button to trigger your build. Now, wait for the build to complete, and it will show you the step results, including the test run.</p><h3>Conclusion</h3><p>This is how you can build a React Native app on Codemagic’s Linux instance as well as test your app. Codemagic provides simple, straightforward, out-of-the-box solutions to achieve your tasks of building, testing and publishing apps without hassle.</p><h3>Links and resources you might be interested in:</h3><ul><li><a href="https://blog.codemagic.io/testing-react-native-apps-with-jest/">Testing React Native apps with Jest and Codemagic</a>.</li><li><a href="https://blog.codemagic.io/react-native-detox-tests-on-codemagic/">React Native Detox Tests on Codemagic</a>.</li><li><a href="https://blog.codemagic.io/mobile-testing-appium-react-native-apps/">Appium Mobile Testing for React Native</a>.</li><li><a href="https://blog.codemagic.io/choosing-the-right-database-for-react-native-app/">Choosing the right database for your React Native app</a>.</li><li><a href="https://blog.codemagic.io/improve-react-native-app-performance/">How to improve performance of a React Native app</a>.</li><li><a href="https://blog.codemagic.io/uploads/covers/thumbnails/codemagic-blog-header-rn-2.png">9 reasons to use Codemagic CI/CD tool for React Native apps in 2021</a>.</li><li><a href="https://blog.codemagic.io/react-native-getting-started-guide-with-codemagic/">Continuous Integration and Delivery for React Native apps</a></li></ul><p><a href="https://medium.com/u/7dc08545ed6d">Sneh Pandya</a> is a Senior Product Manager based in Baroda. He is a community organizer at Google Developers Group and co-host of NinjaTalks podcast. His passion for building meaningful products inspires him to write blogs, speak at conferences and mentor different talents. You can reach out to him over Twitter (<a href="https://twitter.com/snehpandya18">@SnehPandya18</a>).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=814aec5bebe7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/code-well/testing-react-native-apps-with-linux-instances-on-codemagic-814aec5bebe7">Testing React Native apps with Linux instances on Codemagic</a> was originally published in <a href="https://medium.com/code-well">Code Well Mobile</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>