<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/jasmin-aboualdan/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Fri, 03 Apr 2026 12:58:20 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>19256742https://infinum.com/uploads/2024/08/Jailbreak.webp</url>
				</image>
				<title>Is Jailbreak Detection in iOS Apps Still Relevant?</title>
				<link>https://infinum.com/blog/jailbreak-detection-ios-apps/</link>
				<pubDate>Wed, 21 Aug 2024 11:30:11 +0000</pubDate>
				<dc:creator>Jasmin Abou Aldan</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=19256742</guid>
				<description>
					<![CDATA[<p>Explore the world of jailbreak detection in iOS. Is it a necessary safeguard or an outdated precaution? Find out more.</p>
<p>The post <a href="https://infinum.com/blog/jailbreak-detection-ios-apps/">Is Jailbreak Detection in iOS Apps Still Relevant?</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-185"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-36-text js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	While jailbreaking Apple devices is becoming increasingly difficult with every new iOS release, jailbreak detection seems to be lo<strong>sing none of its popularity. Find out if this really is a necessary safeguard or just an outdated precaution.  </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-96">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-97'
	>
	Jailbreak detection in iOS has been a topic of much debate ever since iOS 5. The main reason anyone would want to use a jailbroken device is that iOS is locked, with Apple blocking some software-related features in older OS versions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-99">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-100'
	>
	Generally speaking, jailbreaking refers to the process of removing Apple’s restrictions imposed on iOS or iPadOS by exploiting kernel or OS security vulnerabilities. With a jailbroken device, the user usually gains root access (admin privileges), which allows them to access parts of the OS that are usually restricted to them or install apps not available on the official App Store.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-102">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-103'
	>
	A couple of years and several iOS’s ago, a jailbroken device would allow the user to take advantage of certain features otherwise unavailable to them, like changing wallpapers, using the camera torch as a flashlight, enabling force touch (long press) or Siri on older devices like the iPhone 4. However, iOS is far more customizable today, and most of these features are available on older devices with a simple software update.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-105">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-106'
	>
	Although the number of jailbroken devices is decreasing year by year, introducing a jailbreak detection mechanism still remains a popular request with clients. Not only that, some consider imposing additional restrictions like limiting app usage upon jailbreak detection.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-110"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-108">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-109'
	>
	<a href="https://infinum.com/blog/jailbreaking-bad-why-jailbreak-detection-in-ios-apps-is-pointless/">We found jailbreak detection to be pointless</a> way back in 2019 when we first wrote about it. But what changed over the years? Can the iPhone be jailbroken as easily as before? Is it still important to add jailbreak checks to apps? We’ll answer these questions and provide an overview of the topic from today’s perspective.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-113"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-111">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-112'
	>
	The state of today’s jailbreaking community</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-116"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-114">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-115'
	>
	If you try searching topics such as “how to jailbreak iPhone,” you’ll mostly be offered sketchy websites filled with even sketchier ads, only to realize that most of them are still stuck in the iOS 15 era when jailbreaking was a thing and almost easy to do.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-120"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-117">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-118'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-119'
	>
	<strong>Compared to the early years of jailbreaking, iOS 15 is hard to jailbreak, iOS 16 is nearly impossible, and there is currently no reliable method for iOS 17. With iOS 18 on the horizon, jailbreaking likely won&#8217;t be possible or simply worth the effort.</strong></p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-123"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-121">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-122'
	>
	If you’re persistent in your research, you’ll eventually land on the popular subreddit <a href="https://www.reddit.com/r/jailbreak/" target="_blank" rel="noreferrer noopener">r/jailbreak</a>, where you can easily spend hours sifting through posts only to get the same advice: “Don’t update your iOS 14 or 15 operating system!”. While there are some tools that claim to jailbreak newer versions like iOS 16, most of them only offer rootless jailbreaks (no root access; only limited access to the device&#8217;s file system) or semi-untethered jailbreaks (requiring you to connect your device to a PC and use a jailbreaking tool for each phone reboot).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-126"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-124">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-125'
	>
	One post that caught my attention was titled <a href="https://www.reddit.com/r/jailbreak/comments/182sxks/why_is_jb_dead/" target="_blank" rel="noreferrer noopener">“Why is jb dead?”</a> Most users in the comments agreed that the decline in jailbreaking’s popularity is largely due to Apple incorporating many of the once-desired features directly into iOS. For example, iOS 17 introduced sideloading.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-129"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-127">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-128'
	>
	In addition, many of the biggest names in the jailbreaking community have stopped developing new tools and even discontinued their existing ones, as newer OS versions and highly secure A- and M-series chips have made it nearly impossible to find vulnerabilities that could enable jailbreak.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-132"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-130">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-131'
	>
	It probably also didn’t hurt that in 2022, Apple introduced its <a href="https://security.apple.com/bounty/categories" target="_blank" rel="noreferrer noopener">Security Bounty program</a> with whopping rewards of up to $1 million. This likely pushed a number of researchers and developers out of the jailbreaking community and helped Apple patch more security vulnerabilities that could allow jailbreaking.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-135"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-133">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-134'
	>
	In summary, compared to the early years of jailbreaking, iOS 15 is hard to jailbreak; the available tools are complex and typically only provide partial access to the system, leaving most of it still secured. Jailbreaking iOS 16 is nearly impossible, and there is currently no reliable method to jailbreak iOS 17. With iOS 18 on the horizon, it is questionable whether jailbreaking will be fully possible or even worth the effort.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-138"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-136">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-137'
	>
	How Swift changed the game rules</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-141"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-139">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-140'
	>
	A few years ago, we published our first article on the topic, <a href="https://infinum.com/blog/jailbreaking-bad-why-jailbreak-detection-in-ios-apps-is-pointless/" target="_blank" rel="noreferrer noopener">Why Jailbreak Detection in iOS Apps Is Pointless</a>. In it, we described several jailbreak detection methods and how attackers can bypass them by exploiting Objective-C’s dynamic nature, which relies on a messaging mechanism at runtime. Because Objective-C-based apps cannot be easily obfuscated, they are relatively easy to reverse engineer. As explained in the blog post, this makes it possible to inject malicious code during runtime.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-144"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-142">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-143'
	>
	A few years later, the most widely used programming language on iOS is Swift. The situation has changed because Swift works differently from Objective-C. By nature, Swift is a static language that doesn’t rely on messaging and can be obfuscated. This means that the method for bypassing jailbreak detection mechanisms described in our previous article is no longer applicable with Swift. However, the main conclusion from that post remains just as relevant:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-146"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-18-text-roman js-typography block-highlighted-text__typography'
	data-id='es-145'
	>
	<em>While the process described above might seem simple, it by no means implies that iOS apps lack security. Building truly secure apps includes far more than implementing a simple jailbreak check, and a threat that would justify the effort of blocking app usage based on jailbreak detection would have to be substantial and take copious amounts of work to devise.</em></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-149"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-147">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-148'
	>
	How to handle jailbreak detection today</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-152"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-150">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-151'
	>
	Now that we understand how broadly available jailbreaking is (or isn’t), the question is: what should we do with our apps, and how are we handling this issue with the apps we are developing?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-156"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-153">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-154'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-155'
	>
	<strong>Using the latest SDKs provided by Apple significantly enhances app security, and the key factor in this security is the inability to jailbreak the device.</strong></p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-159"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-157">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-158'
	>
	The first line of defense against jailbreaking is <strong>ensuring your app and operating system are up to date</strong>. Using the latest SDKs provided by Apple significantly enhances app security, and the key factor in this security is the inability to jailbreak the device. By <strong>setting the minimum supported iOS version as high as possible—ideally, the current version plus no more than two previous versions</strong>—you reduce the chances that the app will be run on a jailbroken device to nearly zero.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-162"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-160">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-161'
	>
	This is why we currently recommend our clients set the minimum supported iOS version to iOS 16. With the upcoming release of iOS 18, “current + max 2” will soon mean iOS 16, 17, and 18.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-165"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-163">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-164'
	>
	For example, in one of our ongoing projects, simply by setting the minimum version to iOS 16, we get only 15 out of 4,800 users (0.3%) with jailbroken devices, and those users are well aware of what they’re doing, given how difficult jailbreaking iOS 16 is. Once iOS 18 is released, and if we raise the minimum supported version to iOS 17, the likelihood of any users having jailbroken devices will be virtually nonexistent.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-168"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-166">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-167'
	>
	Generally, when we’re dealing with this issue on our projects, besides employing some common jailbreak detection methods, we also try to determine if any debugger or proxy is connected to the device. In such cases, we stop the app’s execution, as this indicates a high-risk scenario where the attacker may have greater control over both the OS and the app.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-171"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-169">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-170'
	>
	Besides, if we keep in mind that jailbreak detection methods are still the same as in the early days (check if the file can be written to a protected directory, whether there’s a forbidden app installed on the device, etc.) and that these checks are not always effective, taking further measures is possible but unnecessary, as they won’t meaningfully increase the app’s security.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-174"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-172">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-173'
	>
	There’s more to security than jailbreak detection</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-177"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-175">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-176'
	>
	To conclude, adding that extra layer of security to an app is okay, but we shouldn’t restrict app usage based solely on detecting a jailbroken device. Not only does this degrade the user experience without offering meaningful security benefits, but it also prevents more advanced users from using their devices as they see fit, which suggests a “lazy” approach to security.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-180"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-178">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-179'
	>
	Finally, we must remember that, with enough resources and determination, any protection can be broken, and we should not rely only on jailbreak detection or app integrity checks. Securing an app is a far more complex process that includes security measurements on both the backend and the frontend.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-183"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-181">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-182'
	>
	<em>And, as always, if you need any help raising your security posture, you can check out our </em><a href="https://infinum.com/cybersecurity/" target="_blank" rel="noreferrer noopener"><em>cybersecurity services</em></a><em>.</em></p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/jailbreak-detection-ios-apps/">Is Jailbreak Detection in iOS Apps Still Relevant?</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>44799https://infinum.com/uploads/2023/10/From-ugly-duckling-to-beautiful-swan-hero-img.webp</url>
				</image>
				<title>To Refactor or to Rewrite Code? Sometimes You Need Both</title>
				<link>https://infinum.com/blog/refactor-and-rewrite-code/</link>
				<pubDate>Wed, 25 Oct 2023 12:16:23 +0000</pubDate>
				<dc:creator>Jasmin Abou Aldan</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=44799</guid>
				<description>
					<![CDATA[<p>How a major app redesign forced us to face our technical debt and refactor and rewrite our code at the same time.</p>
<p>The post <a href="https://infinum.com/blog/refactor-and-rewrite-code/">To Refactor or to Rewrite Code? Sometimes You Need Both</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-307"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-186">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-189"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-187">
	<p	class='typography typography--size-36-text js-typography block-paragraph__paragraph'
	data-id='es-188'
	>
	<strong><strong>Rushing to meet deadlines or other outside circumstances can sometimes result in less-than-perfect code quality. Met with a major app redesign, we strategically rewrote and refactored our code, transforming our ugly duckling into a beautiful swan.</strong></strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-192"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-190">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-191'
	>
	Many digital products available today started out as small, innocent MVP projects. Sometimes, getting that app out into the world is the main concern, and getting it there quickly matters more than its internal structure, architecture, or other constituent parts that become important as the product grows into a large, multi-screen complexity. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-195"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-193">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-194'
	>
	The reality is, the best architecture in the world can&#8217;t save you if someone beats you to the punch with your app’s core idea.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-198"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-196">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-197'
	>
	Developing a piece of software doesn’t happen in a vacuum, and outside factors often dictate the tempo and feature prioritization, as we’ve had it happen on one of our projects. After years of ongoing work and feature development, we started noticing slowdowns in development as well as other issues. Small fixes started to take longer and longer, and we weren’t happy with our efficiency on the project. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-201"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-199">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-200'
	>
	Then a new, large change request came to us, and we knew we had to do something about our legacy code. It was time for a complete overhaul.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-204"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-202">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-203'
	>
	The road to technical debt is paved with good intentions</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-207"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-205">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-206'
	>
	The project, a mobile banking app for a major client, was around five years in the making at the time. During that period, we added numerous features to the product, both large and small.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-210"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-208">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-209'
	>
	Taking into consideration the project’s initial scope and timeline, and the fact that Swift was still in its early stages, we decided to go with good ol’ Objective-C. Our architecture of choice was a simplified version of VIPER, basically VIPER without a Router and an Interactor. Since time was of issue, we also couldn’t build every little thing from scratch and had to compromise by using some third-party libraries. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-213"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-211">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-212'
	>
	As you can see, it was the perfect breeding ground for a future escalation. I should note that we did do some refactoring and maintenance along the road, as much as time and budget allowed us. First, we switched to the latest version of VIPER, added some new screens using Swift, and adopted a reactive approach to using RxSwift. We also removed almost 70% of the third-party libraries we added initially and replaced them with our own logic.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-215"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-214'
	>
	<strong>After five years, it was time for a major app redesign. Designers poured hours of work into it, and the result was a shiny new look made up of a number of reusable components. However, our codebase wouldn’t be able to handle it easily.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-218"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-216">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-217'
	>
	We knew we wanted to go with the <a href="https://medium.com/@janelle.wg/atomic-design-pattern-how-to-structure-your-react-application-2bb4d9ca5f97" target="_blank" rel="noreferrer noopener">atomic design pattern</a>, but were painfully aware that more than half of our original code could not support this. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-221"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-219">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-220'
	>
	It was time to decide if we wanted to “hack” our current codebase in some way, which would likely give future us more issues to handle down the line, or invest a little more time and perform a more serious intervention.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-224"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-222">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-223'
	>
	Things were quite clear – we had a large technical debt to resolve ASAP.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-227"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-225">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-226'
	>
	To refactor or to rewrite?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-230"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-228">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-229'
	>
	Code refactoring and code rewriting are two buzzwords that are frequently thrown around when discussing how to deal with legacy code. However, they are quite different in their nature.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-233"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-231">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-232'
	>
	Refactoring is a process of changing smaller chunks of code over a period of time while leaving the original logic mostly intact. It is usually done on a smaller scale to keep the codebase easily readable, decrease the number of bugs and their likelihood to occur, improve app performance, etc. Refactoring usually doesn’t take as much time and resources and can be done periodically whenever software developers do something in the module or add new features.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-235"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-234'
	>
	<strong>While refactoring <em>changes</em> small bits of code, rewriting <em>replaces</em> the entire code. After a rewrite, you have brand new code, just like you’d write a screen or a feature from scratch. </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-238"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-236">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-237'
	>
	Code rewrites are usually done only when you have to change more than two-thirds of the code or replace it entirely. In our case, we had to replace Objective-C code with Swift, two programming languages that couldn’t be more different (apart from the fact that they use the same frameworks provided by Apple). </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-241"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-239">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-240'
	>
	Clearly, a complete rewrite takes far more time and resources than a simple refactoring. However, as the old code base full of issues, bugs, and technical debt is removed, we give that module a clean slate.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-244"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-242">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-243'
	>
	For us, both time and resources were a challenge. Whichever approach we chose, we knew that we couldn’t stop an active project so that we could prepare the app for its redesign.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-247"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-245">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-246'
	>
	So, which approach did we choose? Both!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-250"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-248">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-249'
	>
	Time to refactor and rewrite code!</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-253"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-251">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-252'
	>
	We added a few additional software engineers to the project and had a development team ready to transform this ugly duckling into the beautiful swan it is today. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-256"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-254">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-255'
	>
	As mentioned before, more than 80% of the code was not ready for a major redesign since it was largely written in Objective-C and related to the screens we had at the time.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-258"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-257'
	>
	<strong>Our plan was to rewrite the code for the redesigned screens while refactoring some managers, helpers, and formatters to support the new code (and to do a little code cleanup!). </strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-261"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-259">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-260'
	>
	Several team members were responsible for rewriting and refactoring the existing code and redesigning the app using the latest principles and technologies we now use as a standard on all our modern projects. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-264"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-262">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-263'
	>
	At the same time, other team members continued working on new features and bug fixes. Both teams used the same approaches and technologies we agreed on – (Rx)Swift, and the <a href="https://github.com/infinum/ios-viper-xcode-templates" target="_blank" rel="noreferrer noopener">latest version of VIPER</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-267"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-265">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-266'
	>
	The rewrite (redesign) part was done on a separate branch, while refactoring was done on the main branch. We split the rewrite into two major releases. The first release covered around 70% of the app. The second release followed the first one by a few months and covered the remaining 30% of the app.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-270"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-268">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-269'
	>
	As for the new features, the only difference for those two teams was the user interface. While the “rewrite” team used newly created components for the app’s (atomic) redesign, the “maintenance” team worked with the old screens, performing maintenance and adding new features to the “main” branch. As a feature was completed, it was merged on the redesigned branch. That way, the business logic didn’t have to be written more than once, as the “rewrite” team only needed to change the UI.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-273"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-271">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-272'
	>
	This approach sometimes led to double UI interface creation (two different Views in the project), but that was the price we were willing to pay to speed up the whole process.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-276"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-274">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-275'
	>
	The result? Quite impressive, thank you for asking</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-279"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-277">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-278'
	>
	A few months later, we basically had a new project – our beautiful swan. The app became beautiful on the outside, and more importantly, on the inside as well.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-284"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-280">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-281'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-282'
	>
	<strong>Outer beauty turns the head, but inner beauty turns the heart.</strong></p>
		<div class="blockquote__caption-wrap">
			<div	class='typography typography--size-12-text-roman js-typography blockquote__caption'
	data-id='es-283'
	>
	<strong>HELEN J. RUSSEL</strong></div>		</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-287"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-285">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-286'
	>
	Finally, this is what we managed to accomplish: </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-290"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-288">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-289'
	>
	<li>We rewrote the project’s code and went <strong>from around 80% Objective-C to 95% Swift</strong> (mostly reactive)</li><li>By doing that, we <strong>increased our productivity and decreased the time needed to implement new features</strong> by roughly 30% per feature (change request estimations)</li><li>Since most iOS developers starting their career only learn Swift, we <strong>increased the pool of engineers</strong> who can jump on this project</li><li>We <strong>removed more than two-thirds of the third-party libraries</strong>, which reduced the need for third-party library maintenance and <strong>improved our build time</strong></li><li>We <strong>opened the door for new technologies like SwiftUI</strong>, which is already taking hold in the project </li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-293"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-291">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-292'
	>
	At the end of the process, we sent the app to a <a href="https://infinum.com/cybersecurity/penetration-testing/">pentest</a> and got a positive grade. The very nature of Swift (and Apple’s code obfuscation) doesn’t allow a memory dump, which would allow someone to read out class and method names, which was an issue with Objective-C. That code dump can often be used for attacking the app with some sort of a code injection, so this is a large motivation for us to keep rewriting the code until everything is written in Swift.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-296"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-294">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-295'
	>
	It’s never too late to rewrite code</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-299"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-297">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-298'
	>
	We all try to maintain our projects regularly, but as this example shows, without occasional rewrites or at least refactors, an application can fall back in stability and performance. Fixing bugs becomes slower, adding new features more challenging, and scaling the product nearly impossible. Not to mention the accrual of technical debt.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-302"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-300">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-301'
	>
	If you&#8217;re starting to detect code smells and your legacy code is giving you trouble, don’t give up. With a little planning and finding the best approach for your project, it’s not too late to make it shiny and new. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-305"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-303">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-304'
	>
	Maintain your code regularly, and as frequently as possible. You never know when the time will come to turn your ugly duckling into a beautiful swan.&nbsp;</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/refactor-and-rewrite-code/">To Refactor or to Rewrite Code? Sometimes You Need Both</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>43867https://infinum.com/uploads/2023/10/IoT-Security-blogpost-hero-img-min.webp</url>
				</image>
				<title>Secure IoT Connectivity – Safeguarding Your Connected World</title>
				<link>https://infinum.com/blog/secure-iot-connectivity/</link>
				<pubDate>Fri, 13 Oct 2023 09:21:35 +0000</pubDate>
				<dc:creator>Jasmin Abou Aldan</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=43867</guid>
				<description>
					<![CDATA[<p>While IoT connectivity provides endless convenience, most home and office networks used for connected devices are not nearly secure enough. </p>
<p>The post <a href="https://infinum.com/blog/secure-iot-connectivity/">Secure IoT Connectivity – Safeguarding Your Connected World</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-514"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-308">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-311"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-309">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-310'
	>
	<strong>In a world where we’re enjoying the convenience of IoT connectivity and everything from our heating system to our blender connects to the internet, security is often overlooked. Breaches can and do happen, but fortunately, there are steps you can take to make your network more secure.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-314"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-312">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-313'
	>
	More often than not, we hear about certain security issues connected with the <a href="https://infinum.com/custom-iot-solutions/" target="_blank" rel="noreferrer noopener">Internet of Things</a> (IoT). But do you know how severe these issues can potentially be? Working at a tech company and always surrounded by techy people, I had a general idea. However, digging deeper into this rabbit hole, I realized that the situation was worse than I expected.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-317"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-315">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-316'
	>
	But let’s back up. Internet of Things is a term used to describe a network of interrelated devices or other objects that can be connected to the Internet. It’s like a social network, but instead of connecting people, IoT connects various devices.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-320"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-318">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-319'
	>
	<a href="https://infinum.com/blog/iot-from-evolution-to-revolution/" target="_blank" rel="noreferrer noopener">IoT solutions have the power to make our lives easier in a number of ways</a>. However, it also comes with some inherent risks. To protect our home network, we first need to understand them. And to tackle these risks and make our home network as secure as possible, we suggest a simple IoT connectivity configuration you can use.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-326"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<a	class="card-simple js-card-simple card-simple--is-ad block-card__card-simple card-simple--has-link js-card-simple-link card-simple__content-align--left"
	data-id="es-321"
	 target='_blank' rel='noopener noreferrer' href='https://infinum.com/iot-implementation/'>

	
	
	<div class="card-simple__content">
		<div class="card-simple__heading-wrap">
			<h2	class='typography typography--size-24-text js-typography card-simple__heading'
	data-id='es-322'
	>
	From strategy to deployment, we cover all aspects of IoT development lifecycle. <strong>Download our Guide to Successful IoT Implementation</strong>.</h2>		</div>

		<button	class="btn btn--color-infinum btn--size-small btn--width-default btn__icon-position--right card-simple__btn js-block-card-btn js-card-simple-link"
	data-id="es-323"
	 tabindex='-1'>
		<div class="btn__inner">
					<div	class='typography typography--size-none js-typography btn__label'
	data-id='es-324'
	>
	Learn more</div>		
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-325'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>	</div>
</a>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-329"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-327">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-328'
	>
	IoT connectivity – convenience comes at a price</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-332"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-330">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-331'
	>
	An IoT device can be almost anything. <a href="https://infinum.com/work/philips-masterconnect-iot-lighting/" target="_blank" rel="noreferrer noopener">A smart lighting system</a>, <a href="https://infinum.com/news/infinum-and-philips-award-winning-collaboration-on-nutriu/" target="_blank" rel="noreferrer noopener">kitchen appliances like air fryers or coffee machines</a>, blinds, a TV, air conditioner, heating, security cameras, you name it. If it can connect to the internet, it’s IoT.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-335"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-333">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-334'
	>
	This wide range of <a href="https://infinum.com/iot-solution-development/" target="_blank" rel="noreferrer noopener">IoT devices</a> can be very beneficial in making your life easier. Decentralized smart heating combined with some automatizations can reduce your heating costs, and you get to wake up in the morning to a warm home. Smart lighting can reduce power consumption by automatically turning the lights on or off depending on room occupancy. Automatic shades can let the sun in the morning for your house plants to enjoy even when you are not at home.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-337"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-336'
	>
	<strong>Even a smart vacuum cleaner can give you some extra time in your busy life. It can clean your home while you’re at work, so you can spend more time with your loved ones once you get back.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-340"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-338">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-339'
	>
	All that is convenient, but when we start thinking about IoT security, the question is, what price are we willing to pay for the convenience of our connected devices? </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-343"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-341">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-342'
	>
	Is it IoT? Smart devices and connectivity</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-346"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-344">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-345'
	>
	Before we dig deep into security issues, we need to be on the same page about the types of devices we’re talking about. Any device that has a screen and/or can be automated to an extent is considered smart. For example, this would be a coffee machine equipped with a number of stored recipes, a lamp connected to a movement sensor, etc.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-349"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-347">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-348'
	>
	However, smart doesn’t necessarily mean IoT. For a device to be considered IoT, it needs to be connected to the internet – directly over WiFi or Ethernet, to an online server, or via a different device like a mobile phone using Bluetooth (usually BLE – Bluetooth Low Energy).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-352"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-350">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-351'
	>
	It is precisely for this reason that IoT connectivity may pose a security threat.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-355"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-353">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-354'
	>
	Security breaches don’t only happen to corporations</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-358"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-356">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-357'
	>
	<a href="https://www.theguardian.com/technology/2016/oct/26/ddos-attack-dyn-mirai-botnet" target="_blank" rel="noreferrer noopener">One of the most famous security breaches</a> happened in 2016 when a DDoS attack was deployed from several unsecured IoT devices like cameras and DVR players. The attack, aimed at the DNS provider Dyn, brought down a large part of America’s internet for a couple of hours, including Twitter, Netflix, Reddit, and CNN.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-361"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-359">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-360'
	>
	Or, more recently, the <a href="https://thehackernews.com/2024/09/new-raptor-train-iot-botnet-compromises.html" target="_blank" rel="noreferrer noopener">Raptor Train</a>. A botnet of more than 200,000 compromised connected devices was hijacked through unpatched vulnerabilities and insecure defaults &#8211; not because those companies lacked internal security policies, but because the products themselves were never designed or maintained with long-term security in mind.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-368"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<a	class="card-simple js-card-simple card-simple--is-ad block-card__card-simple card-simple--has-link js-card-simple-link card-simple__content-align--left"
	data-id="es-362"
	 href='https://infinum.com/blog/cyber-resilience-act/'>

	
	
	<div class="card-simple__content">
		<div class="card-simple__heading-wrap">
			<h2	class='typography typography--size-24-text js-typography card-simple__heading'
	data-id='es-363'
	>
	This kind of large-scale product risk is exactly what the EU’s Cyber Resilience Act (CRA) is meant to address.</h2>		</div>

		<p	class='typography typography--size-16-text-roman js-typography card-simple__paragraph'
	data-id='es-364'
	 id='es-362-paragraph'>
	If you’re building products for, or are part of the supply chain behind nearly 21 billion connected devices worldwide, you might already share responsibility under the CRA.</p><button	class="btn btn--color-infinum btn--size-small btn--width-default btn__icon-position--right card-simple__btn js-block-card-btn js-card-simple-link"
	data-id="es-365"
	 tabindex='-1'>
		<div class="btn__inner">
					<div	class='typography typography--size-none js-typography btn__label'
	data-id='es-366'
	>
	<strong>Learn if you’re in scope</strong></div>		
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-367'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>	</div>
</a>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-371"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-369">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-370'
	>
	However, attacks don’t only happen to large businesses; with millions of devices out in the world, regular users are just as exposed. A few years back, <a href="https://www.bitdefender.com/files/News/CaseStudies/study/294/Bitdefender-WhitePaper-RDoor-CREA3949-en-EN-GenericUse.pdf" target="_blank" rel="noreferrer noopener">Amazon’s internet-connected doorbell Ring presented security issues</a> that could allow attackers to breach a home network.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-373"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-372'
	>
	<strong>Cyber attacks are often made possible by simple cost cuts. IoT devices using cheaper components may be unable to execute firmware updates that could fix vulnerabilities. Some devices were even initially deployed with firmware that contained known vulnerabilities</strong>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-376"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-374">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-375'
	>
	Another potential security risk in IoT connectivity arising from cost cuts is unsecured communication between the device and the vendor’s server. To secure a connection with standards like Transport Layer Security (TLS), vendors would need to use more powerful hardware, increasing the device price and likely reducing sales figures.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-379"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-377">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-378'
	>
	On the other hand, connected devices are not always the ones to blame. The majority of the attacks are deployed successfully because of improper password protection. Strong passwords are rarely used, and surveys find that over 50% of people reuse their passwords. Combined with unsecured IoT connectivity, and if the attacker deploys traffic sniffing, they can easily obtain a user’s password – an entry point to anything they own (e.g., social network, email, cloud drive…).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-382"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-380">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-381'
	>
	Home networks – often more breachable than not</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-385"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-383">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-384'
	>
	Let’s see how this translates to our everyday, home-network level. Since I work in the tech industry, my first instinct was to ask fellow colleagues about their home network setup. I ran a small survey among IoT enthusiasts, and the results regarding IoT connectivity security were pretty much as expected. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-388"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-386">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-387'
	>
	Around 40% of respondents have some sort of a secured network on top of the service provider’s router. 30% use default ISP routers with network security configurations, and the remaining 30% do not secure their IoT network. If IT professionals don’t care about network security, we can assume that most “regular” users care even less.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-391"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-389">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-390'
	>
	One of the main issues here is that most people won&#8217;t use separate networks at home. The IoT devices are usually connected to the same home network as our personal devices – local data storage (e.g., Network Attached Storage &#8211; NAS), work computers, mobile devices, etc. The reason probably lies in the fact that most users will get some (generally cheap) router from the ISP (Internet Service Provider) that can not be configured in any way. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-394"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-392">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-393'
	>
	Moreover, many users tend to keep the default settings even when a better router is provided by the ISP, thus missing the chance to make their network more secure. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-397"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-395">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-396'
	>
	How to manage IoT connectivity in a secure way?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-400"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-398">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-399'
	>
	As a person who uses pretty much everything imaginable connected to the internet, like smart switches, lights, heating, cooling, air purifying, <a href="https://infinum.com/blog/improving-ux-in-nutriu-by-combining-iot-and-mobile-app-data/" target="_blank" rel="noreferrer noopener">kitchen appliances</a>, blinds, etc., I felt that at some point, my local network became more exposed, and I could quickly become a victim of an attack. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-403"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-401">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-402'
	>
	To secure our private data from breaches, we would need to do some network segmentation, i.e., separate the IoT traffic from the rest of the home traffic. That way, an IoT device will have access to the internet, but not to the other devices using the network. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-406"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-404">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-405'
	>
	To accomplish this, we have to use a router. Acting as our network’s “brain”, a router will help us separate those devices from everything else on our network.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-409"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-407">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-408'
	>
	Hardware limitations</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-412"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-410">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-411'
	>
	Before we get into network configuration, we should note that the suggested course of action for secure IoT connectivity will not be possible on any router. Most routers provided by the ISP will be locked and therefore not so configurable. You may be able to create some firewall rules, but without proper network separation, that’s only half of the job, and your network won’t be as secure as it should be. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-415"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-413">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-414'
	>
	As we invest in smart home devices, we should also invest in the equipment that connects those devices to the network. It doesn’t have to be a major investment. Any router that can run <a href="https://dd-wrt.com/support/router-database/" target="_blank" rel="noreferrer noopener">DD-WRT</a> or <a href="https://openwrt.org/supported_devices" target="_blank" rel="noreferrer noopener">OpenWRT</a> will do the trick. However, if you are prepared to invest more seriously into your home network, you’ll find some very powerful routers from well-known brands.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-418"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-416">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-417'
	>
	Network configuration</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-421"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-419">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-420'
	>
	In this configuration, the idea is to separate your local network into a few smaller virtual networks. We can do this by “tagging” our local network traffic, so our router knows which device is responsible for the traffic.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-424"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-422">
	<h4	class='typography typography--size-30-text js-typography block-typography__typography'
	data-id='es-423'
	>
	Separating a local network with VLANs and tagging</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-427"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-425">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-426'
	>
	VLAN is a virtual network created on top of our local network. When VLAN networks are employed, the traffic that enters our local network will have an assigned “ID”, a number that identifies one virtual network from another and, therefore, the traffic coming from one device from that of another.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-431"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-428">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-429'
	>
	1</p>	<div class="bullet__content">
		<h5	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-430'
	>
	Network tagging (create VLAN)</h5>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-434"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-432">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-433'
	>
	Let’s say we want to create three Virtual LANs. Let’s name the first one “Trusted”, and connect all of our personal devices (e.g., laptops, mobile phones, tablets, etc.). We can then assign it the ID (tag) 10 and set the local IP range of 192.168.<strong>10</strong>.X.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-437"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-435">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-436'
	>
	The next step is to create a new VLAN called “IoT”<strong>,</strong><strong><em> </em></strong>and connect all the IoT devices (e.g., lights, TVs, heating) to it. Its ID will be 20, and we’ll set the range to 192.168.<strong>20.</strong>X.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-440"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-438">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-439'
	>
	And last but not least, we’ll create a “Guest” VLAN for all the guests that we want to share our network with. We’ll use the tag 30 and the range 192.168.<strong>30</strong>.X.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-443"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-441">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-442'
	>
	<em>Disclaimer: the tag numbers used are arbitrary. You can use any number you want (e.g., 100, 200, 300, etc.). The IP ranges are also optional but can help to easily identify the devices on the network.</em></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-447"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-444">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-445'
	>
	2</p>	<div class="bullet__content">
		<h5	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-446'
	>
	Assign VLAN to switch ports</h5>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-450"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-448">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-449'
	>
	Once we’ve created the virtual networks, we should assign them to the router&#8217;s switch ports or an additional switch. So, the “IoT” VLAN should be connected to all the ports an IoT device is connected to.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-454"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-451">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-452'
	>
	3</p>	<div class="bullet__content">
		<h5	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-453'
	>
	Assign VLAN to WiFi</h5>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-457"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-455">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-456'
	>
	The same applies to our wireless network. We have to create a new WiFi network, for example, “My Network IoT”, and we should assign the “IoT” VLAN network to it. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-461"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-458">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-459'
	>
	4</p>	<div class="bullet__content">
		<h5	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-460'
	>
	Connect devices to assigned networks</h5>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-464"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-462">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-463'
	>
	Connect all the devices to their appropriate switch ports or wireless networks, and we can move on to the next part of the configuration.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-467"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-465">
	<h4	class='typography typography--size-30-text js-typography block-typography__typography'
	data-id='es-466'
	>
	Creating a firewall for IoT devices</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-470"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-468">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-469'
	>
	A firewall is a network security system that monitors and filters all incoming and outgoing traffic, based on some established security rules. When we employ a firewall for IoT devices, we create a barrier between our devices and our personal computer or NAS.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-474"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-471">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-472'
	>
	1</p>	<div class="bullet__content">
		<h5	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-473'
	>
	Allow trusted traffic</h5>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-477"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-475">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-476'
	>
	The first rule we create should <strong>allow</strong> <strong>all traffic</strong> from our “Trusted” VLAN to the “IoT” VLAN. That way, we can be connected to our smart home devices, but only in the direction <em>from</em> “my personal computer” <em>to</em> “my smart light”. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-481"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-478">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-479'
	>
	2</p>	<div class="bullet__content">
		<h5	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-480'
	>
	Block “IoT” (and other networks, e.g., “Guest”) traffic toward trusted devices</h5>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-484"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-482">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-483'
	>
	Next, we should block the traffic coming from the opposite direction. So, let’s create a few more rules!&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-487"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-485">
	<p	class='typography typography--size-20-text-roman js-typography block-typography__typography'
	data-id='es-486'
	>
	This rule will <strong>block all traffic </strong>from the “IoT” VLAN to all the other VLANs (i.e., “Trusted” and “Guest”). That way, when my smart light tries to connect to my personal computer, the firewall for IoT devices will block (or drop) that traffic, and the light will not be able to access the computer.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-490"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-488">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-489'
	>
	The same approach should be used for other VLANs. In our example, that would mean adding a “Guest” network rule to <strong>block all traffic </strong>from the “Guest” VLAN to all the other VLANs.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-494"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-491">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-492'
	>
	3</p>	<div class="bullet__content">
		<h5	class='typography typography--size-24-text js-typography bullet__heading'
	data-id='es-493'
	>
	Customize your setup (optional) </h5>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-497"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-495">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-496'
	>
	Following these steps, you&#8217;ll separate the traffic on your home network. However, if you want to play with your network a little more, you can fine-tune it any way that suits you. For example, we run our smart home assistant applications on a tablet. Even if we have blocked IoT devices’ communication with the rest of the network, we can allow communication only on specific <a href="https://www.cloudflare.com/en-gb/learning/network-layer/what-is-a-computer-port/" target="_blank" rel="noreferrer noopener">ports</a>. That way, the devices can communicate with the smart home assistants, while the tablet itself remains connected to the “Trusted” network.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-500"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-498">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-499'
	>
	Make your home smart, but be smart about security</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-503"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-501">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-502'
	>
	In conclusion, we can safely assume that most devices on the market lack adequate security measures, especially within the context of IoT connectivity. Knowing that there are more IoT devices than people on this planet, chances are that we have at least one unsecured device in our homes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-506"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-504">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-505'
	>
	If you have just a few devices, you are probably safe, and you should be fine applying some basic firewall rules on your ISP router. In this case, investing in your network can only be a bonus.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-509"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-507">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-508'
	>
	However, if you decide to make your home or office as smart as it can be, using many different <a href="https://infinum.com/custom-iot-solutions/" target="_blank" rel="noreferrer noopener">IoT devices</a>, you should consider investing in your home network. Not just the hardware, but also a better network configuration using VLANs and firewalls.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-512"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-510">
	<p	class='typography typography--size-20-text-blog-roman js-typography block-typography__typography'
	data-id='es-511'
	>
	<em>To discover what else we can do with IoT connectivity, check out our <a href="https://infinum.com/custom-iot-solutions/" target="_blank" rel="noreferrer noopener">IoT solutions page.</a></em></p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/secure-iot-connectivity/">Secure IoT Connectivity – Safeguarding Your Connected World</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>42651https://infinum.com/uploads/2023/09/Blogpost-hero-img-The-Power-of-Shell-Script-in-Xcode-min.webp</url>
				</image>
				<title>Harness the Full Power of Custom Xcode Shell Scripts</title>
				<link>https://infinum.com/blog/xcode-shell-scripts/</link>
				<pubDate>Wed, 20 Sep 2023 16:20:18 +0000</pubDate>
				<dc:creator>Jasmin Abou Aldan</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=42651</guid>
				<description>
					<![CDATA[<p>Writing your own Xcode shell scripts opens up a world of possibilities. We demonstrate this on a common use case – checking the SSL pinning certificate.</p>
<p>The post <a href="https://infinum.com/blog/xcode-shell-scripts/">Harness the Full Power of Custom Xcode Shell Scripts</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-563"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-515">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-518"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-516">
	<p	class='typography typography--size-36-text js-typography block-paragraph__paragraph'
	data-id='es-517'
	>
	Pre-made scripts are cool, but writing your own Xcode shell scrips opens up a world of possibilities for making developers’ lives easier. We demonstrate this on one potential use case – checking the SSL pinning certificate.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-521"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-519">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-520'
	>
	If you’re an iOS developer, chances are you use some sort of a bash command on our Xcode projects on a daily basis, even if you’re unaware of it. If you are using Cocoapods, just check the Build Phases of your project. You will find the <code>Run Script Phase</code> named <code>Check Pods Manifest.lock</code>. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-524"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-522">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-523'
	>
	If you are using Universal Frameworks in your project, you will also have some sort of a <code>Strip unused architecture</code> script. These pre-made scripts are cool, but Xcode shell scripts can make our lives easier in many different ways. So let’s dive in and see how we can utilize them. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-527"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-525">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-526'
	>
	Reduce the hassle with custom Xcode shell scripts</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-530"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-528">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-529'
	>
	Writing our own Xcode shell scripts opens up many possibilities. We’ll illustrate this on a use case we’ve chosen as our example: checking the SSL pinning certificate validity date.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-533"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-531">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-532'
	>
	Use case: SSL Pinning certificate check</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-536"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-534">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-535'
	>
	We often want to make our apps more secure, especially those that involve sensitive user data (i.e.,<a href="https://infinum.com/work/?industries=finance-insurance" target="_blank" rel="noreferrer noopener"> mobile banking applications</a>). One of the most common ways of doing that is by using <a href="https://infinum.com/blog/ssl-pinning-revisited/" target="_blank" rel="noreferrer noopener">SSL pinning</a>. As it says in the blog post, </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-540"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-537">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-538'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-539'
	>
	[when] pinning public keys from certificates, you can either pin the certificates themselves (in which case you do a byte-per-byte data comparison) or just compare the public keys in the certificates.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-543"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-541">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-542'
	>
	For the sake of this example, let’s say we are using a certificate check rather than a public key. Considering that certificates usually have an expiration time of two years, you’ll have to track the validity date so your app doesn’t suddenly stop working.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-546"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-544">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-545'
	>
	The expiration date is easy to miss. It’s a common scenario that everyone goes crazy a couple of days before the expiration because a new certificate is issued, and the app has to include it.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-549"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-547">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-548'
	>
	In this case, there is little time to create an app update and review the testing required for the certificate update. What’s more, that kind of test could result in a couple of hours of downtime for the users as their app is still not ready for the new certificate. This is bad UX and can bring about negative comments from the community. So, let’s see how a custom script can help us out here.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-552"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-550">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-551'
	>
	Certificate validity check script</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-555"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-553">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-554'
	>
	To check the certificate’s validity, we will use two main components in our script:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-558"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-556">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-557'
	>
	<li><code>openssl</code> — used for converting our certificate from <code>.der</code> into the <code>.pem</code> and checking date validity;</li><li><code>osascript </code>— UNIX-based command for running <a href="https://ss64.com/osx/osascript.html" target="_blank" rel="noreferrer noopener">AppleScripts</a>.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-561"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-559">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-560'
	>
	In your project, go to the <code>Build Phases</code> and add the <code>New Run Script Phase</code> named <em>Check Certificates Validity</em>.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-566"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-564"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-565">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2023/09/In-article-02-The-Power-of-Shell-Script-in-Xcode-1400x536.webp				media='(max-width: 699px)'
				type=image/webp								height="536"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2023/09/In-article-02-The-Power-of-Shell-Script-in-Xcode.webp"
					class="image__img block-media__image-img"
					alt=""
										height="908"
															width="2372"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-619"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-570">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-569"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-567">
	</div>	</div>
</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-573"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-571">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-572'
	>
	You can find the entire script in this <a href="https://gist.github.com/jabou/f29ca476154ebe4fcb3867cc64afbc9b">code snippet</a>.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-576"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-574">
	<p	class='typography typography--size-20-text-roman js-typography block-paragraph__paragraph'
	data-id='es-575'
	>
	Let’s dive in:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-578"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-python github-light" data-language="python" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> 1 Create cache file for storing last shown date</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">...</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">PROJECT_CACHE</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #d73a49;">~</span><span class="token" style="color: #d73a49;">/</span><span class="token">.</span><span class="token">cache</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token">(</span><span class="token">basename</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">--</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token">(</span><span class="token">find</span><span class="token"> </span><span class="token">.</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">name</span><span class="token"> </span><span class="token" style="color: #d73a49;">*</span><span class="token">.</span><span class="token">xcworkspace</span><span class="token">)</span><span class="token">)</span><span class="token">.</span><span class="token">txt</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> 2 Variables</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">CERTIFICATES</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">$</span><span class="token" style="color: #005cc5;">{PROJECT_DIR}</span><span class="token" style="color: #032f62;">/MyProject/SupportingFiles/Certificates/</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">REMIND_IN</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">2</span><span class="token"> </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> 2 months</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">LAST_CHECK</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token">(</span><span class="token">head</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">n</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token" style="color: #005cc5;">PROJECT_CACHE</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">...</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> 3 Check validity of each certificate</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">for</span><span class="token"> </span><span class="token">cert</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token">(</span><span class="token">find</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">$CERTIFICATES</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">name</span><span class="token"> </span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">*.der</span><span class="token" style="color: #032f62;">&#039;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">do</span><span class="token"> 
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> 4 Convert to .pem for validity date check</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">...</span><span class="token">
</span></span><span class="line"><span class="token">openssl</span><span class="token"> </span><span class="token">x509</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">inform</span><span class="token"> </span><span class="token">der</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #d73a49;">in</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token">cert</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">out</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token" style="color: #005cc5;">TEMP_CERT</span><span class="token"> 
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> 5 Check validity</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">openssl</span><span class="token"> </span><span class="token">x509</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">checkend</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token" style="color: #005cc5;">REMINDER_TIME</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">noout</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #d73a49;">in</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token" style="color: #005cc5;">TEMP_CERT</span><span class="token">; </span><span class="token">then</span><span class="token">
</span></span><span class="line"><span class="token">echo</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Certificate $CERT_NAME is still valid</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">else</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">EXPIRY_DATE</span><span class="token" style="color: #d73a49;">=</span><span class="token">(</span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token">(</span><span class="token">openssl</span><span class="token"> </span><span class="token">x509</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">enddate</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">noout</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token" style="color: #d73a49;">in</span><span class="token"> </span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token" style="color: #005cc5;">TEMP_CERT</span><span class="token" style="color: #d73a49;">|</span><span class="token">cut</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">d</span><span class="token">= </span><span class="token" style="color: #d73a49;">-</span><span class="token">f</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> Create message</span><span class="token">
</span></span><span class="line"><span class="token">fi</span><span class="token">
</span></span><span class="line"><span class="token">done</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> 6 Alert user</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">CERTIFICATE_WARNING</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">The following certificates expire in $REMIND_IN...</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">OSASCRIPT_MESSAGE</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token">(</span><span class="token">printf</span><span class="token"> </span><span class="token" style="color: #032f62;">&#039;</span><span class="token" style="color: #032f62;">tell app &quot;Xcode&quot; to display dialog &quot;</span><span class="token" style="color: #005cc5;">%s</span><span class="token" style="color: #032f62;">&quot; with title &quot;Certificates validity&quot; with icon caution buttons {&quot;OK&quot;} default button &quot;OK&quot;</span><span class="token" style="color: #032f62;">&#039;</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">$CERTIFICATE_WARNING</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">osascript</span><span class="token"> </span><span class="token" style="color: #d73a49;">-</span><span class="token">e</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">$OSASCRIPT_MESSAGE</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-581"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-579">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-580'
	>
	Let&#8217;s take it step by step:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-585"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-582">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-583'
	>
	1</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-584'
	>
	This script will be triggered every time we build the project, so we will store the date of the last check in the cache and show the alert only on the first app build of the day, as long as we have an <em>expiring</em> certificate in the project.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-589"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-586">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-587'
	>
	2</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-588'
	>
	We should define some global variables, such as a path to the certificates, a temporary directory for converted certificates, reminder time, etc.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-593"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-590">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-591'
	>
	3</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-592'
	>
	After the temporary folder is created, we will iterate through the certificates in our project.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-597"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-594">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-595'
	>
	4</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-596'
	>
	Every certificate should be converted from binary <code>.der</code> format to the <code>.cer</code> format since we cannot read the date from binary data.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-601"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-598">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-599'
	>
	5</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-600'
	>
	Check if the date comes after the 2-month period. If it does, it’s all good, but if the certificate’s expiration date falls within this time period, its name will be appended to the list of certificates that require updating.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-605"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-602">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-603'
	>
	6</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-604'
	>
	If there are some certificates with validity warnings, and this is the first time in the day when we should be alerted, we will assemble the command for <code>osascript</code>. Since the AppleScript format is intended to be human-readable for easy use, our command will basically be the following:</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-607"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #005cc5;">tell</span><span class="token"> </span><span class="token" style="color: #005cc5;">app</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Xcode</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #005cc5;">to </span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">    display</span><span class="token"> </span><span class="token" style="color: #005cc5;">dialog</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">%s</span><span class="token" style="color: #032f62;">&quot;</span><span class="token"> </span><span class="token" style="color: #005cc5;">with</span><span class="token"> </span><span class="token" style="color: #005cc5;">title</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Certificates validity</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #005cc5;"> </span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">    with</span><span class="token"> </span><span class="token" style="color: #005cc5;">icon</span><span class="token"> </span><span class="token" style="color: #005cc5;">caution </span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">    buttons</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">OK</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">}</span><span class="token" style="color: #005cc5;"> </span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">    default</span><span class="token"> </span><span class="token" style="color: #005cc5;">button</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">OK</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-611"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-608">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-609'
	>
	7</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-610'
	>
	Run AppleScript, save today’s date in the cache and remove the temporarily created certificates from the project.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-614"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-612">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-613'
	>
	End result</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-617"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-615">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-616'
	>
	AppleScript is executed by a custom Xcode shell script. Our build will be paused as long as this alert stays active. Once the alert is dismissed, the build will continue, so you can’t miss it.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-622"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-620"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-621">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2023/09/in-article-01-The-Power-of-Shell-Script-in-Xcode-mobile.webp				media='(max-width: 699px)'
				type=image/webp								height="1690"
												width="2372"
				 />
												<img
					src="https://infinum.com/uploads/2023/09/In-article-01-The-Power-of-Shell-Script-in-Xcode.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1378"
															width="2372"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-640"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-626">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-625"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-623">
	</div>	</div>
</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-629"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-627">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-628'
	>
	Get creative with Xcode shell scripts</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-632"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-630">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-631'
	>
	As you can see, a few simple lines of code can make our projects as predictive and as secure as we want our apps to be.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-635"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-633">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-634'
	>
	This was just one example of the power of Xcode shell scripts. Combining them, you could create much more automatizations in your projects than you think. For example, you could create universal frameworks, strip unused architectures, use one main <code>.plist</code> file that is re-written with different data depending on the scheme you are running, make #TODO show as a warning, etc. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-638"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-636">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-637'
	>
	With a little creativity, you can get Xcode to make your life and coding much easier.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/xcode-shell-scripts/">Harness the Full Power of Custom Xcode Shell Scripts</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7981https://infinum.com/uploads/2020/04/implementing-dynamic-color-themes-in-your-ios-app-0.webp</url>
				</image>
				<title>Implementing Dynamic Color Themes in Your iOS App</title>
				<link>https://infinum.com/blog/implementing-dynamic-color-themes-in-your-ios-app/</link>
				<pubDate>Fri, 24 Apr 2020 16:56:00 +0000</pubDate>
				<dc:creator>Jasmin Abou Aldan</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/implementing-dynamic-color-themes-in-your-ios-app/</guid>
				<description>
					<![CDATA[<p>What&#8217;s cooler than implementing dark mode? Learning to paint your app whatever color palette you want — dynamically, in runtime.</p>
<p>The post <a href="https://infinum.com/blog/implementing-dynamic-color-themes-in-your-ios-app/">Implementing Dynamic Color Themes in Your iOS App</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-889"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-641">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-644"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-642">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-643'
	>
	As iOS 13 has become available on more than 70% of the iOS devices, dark mode has been getting great support from iOS developers every day.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-647"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-645">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-646'
	>
	However, sometimes you want to go beyond the monochromatic color scheme and brighten up your app with a lively shade.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-650"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-648">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-649'
	>
	Before we delve into implementing dynamic color schemes we recommend you check out our <a href="https://infinum.com/blog/color-naming-system-ios/" target="_blank" rel="noreferrer noopener">Bullet-Proof Color-Naming System for iOS Development</a>. The system offers a structured approach to color-naming, and also makes it easier to add dark mode support. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-653"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-651">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-652'
	>
	The white &amp; black approach</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-656"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-654">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-655'
	>
	Imagine you have to create a new app with the functionality to rent your branded car. Currently, there are only three models available for rent: X, Y, and Z. The app should be able to show basic information about each car, availability, and the possibility to rent it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-659"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-657">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-658'
	>
	That UI could look something like this.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-662"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-660"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-auto" data-id="es-661">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2021/12/implementing-dynamic-color-themes-in-your-ios-app-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="944"
															width="300"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-665"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-663">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-664'
	>
	It would be quite easy to modify the UI to support dark mode, but now the designer has sent us a proposal for another cool feature – every car should have its own color.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-668"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-666">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-667'
	>
	How to make apps dynamically colorful?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-671"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-669">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-670'
	>
	The implementation should support as many themes as the designer wants, as well as any number of screens and components that might be themable as a result of that design proposal.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-674"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-672"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-673">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2021/12/implementing-dynamic-color-themes-in-your-ios-app-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="944"
															width="1322"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-677"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-675">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-676'
	>
	There are a few possible approaches to adding color functionality, some better than others.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-680"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-678">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-679'
	>
	1. Theme-specific ViewController?&#x200d;</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-683"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-681">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-682'
	>
	This approach comes naturally to everyone faced with such a problem. Basically, inside <code>viewWillAppear</code> it’s possible to assign a color, font, image, etc. to the UI elements by checking which theme was last selected. Theme selection can be stored in <code>UserDefaults</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-686"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-684">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-685'
	>
	What are the flaws to that approach? Well, the problem occurs the first time when adding a new element, i.e. next time when adding a new view controller. There is no way to keep track of every element that is added to <code>viewWillAppear</code> so that the correct color or font is set.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-691"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-687">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-688'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-689'
	>
	The code gets cluttered faster this way.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-694"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-692">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-693'
	>
	Also, sometimes it’s not even desirable to connect our UI with our code (e.g. static labels that don’t have to be localized or changed in runtime). When adding a new view controller, also account for the extra time necessary to implement the logic for color change (duplicated code).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-697"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-695">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-696'
	>
	However, the biggest problem with this approach is theme reloading, which will introduce multiple bugs. For example, when changing the theme on the currently active screen, it will not be changed without somehow reloading the entire screen, which will either look ugly, or cause a screen flicker.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-700"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-698">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-699'
	>
	2. App reloading?&#x200d;</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-703"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-701">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-702'
	>
	The second approach can fix some things from the first one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-706"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-704">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-705'
	>
	If you ignore the problem of connecting every UI component to our code and code duplications for a moment, you would be able to reload the entire app, i.e. change the navigation stack so that the user is on the first screen in the app every time the theme is changed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-709"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-707">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-708'
	>
	Even if this fixes the initial problem with the UI reloading, there will now be a new problem — the app state.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-714"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-710">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-711'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-712'
	>
	The user will lose the session, a new login should be made, and maybe the setup of the app should be done again.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-717"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-715">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-716'
	>
	This could be fixed by trying to store the last known app state, but as the app becomes bigger and bigger, this will increase the complexity linearly for such a small feature. So, this is a no-go as well.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-720"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-718">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-719'
	>
	3. Notification and subscription</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-723"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-721">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-722'
	>
	Getting warmer but not quite there yet.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-726"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-724">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-725'
	>
	You could create a subscription to <code>NotificationCenter</code> in every view controller and post a notification that will trigger UI reloading whenever theme change occurs. The problem of reloading and app state is solved in this approach.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-731"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-727">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-728'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-729'
	>
	There’s still the problem of cluttered, error-prone code in which a component could be easily forgotten.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-734"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-732">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-733'
	>
	4. Protocol-oriented theming</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-737"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-735">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-736'
	>
	We have a winner!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-740"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-738">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-739'
	>
	The two key components here are <code>UIAppearance</code> and <code>Protocols</code> . Let’s see how these two small but powerful things can help us implement any color.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-743"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-741">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-742'
	>
	<strong>UIAppearance</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-746"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-744">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-745'
	>
	As official documentation says, <code>UIAppearance</code> is a collection of methods that grants access to the appearance proxy for a class. It is a protocol which returns a proxy that forwards any configuration to instances of a particular class.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-749"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-747">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-748'
	>
	Once config is received, it is applied when a class is added to the window hierarchy and can be applied to all instances of a class, or classes contained within a certain hierarchy structure.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-751"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">UILabel.</span><span class="token">appearance(</span><span class="token">)</span><span class="token">.</span><span class="token">textColor</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> .</span><span class="token">red</span><span class="token">
</span></span><span class="line"><span class="token">UINavigationBar.</span><span class="token">appearance(</span><span class="token">)</span><span class="token">.</span><span class="token">barStyle</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> blackTranslucent
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-754"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-752">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-753'
	>
	There is the problem of every <code>UILabel</code> contained in our hierarchy having red text color. To solve this, use <code>whenContainedInInstancesOf</code> :</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-756"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">UILabel.</span><span class="token">appearance(</span><span class="token">whenContainedInInstancesOf:</span><span class="token"> [CustomViewController.</span><span class="token" style="color: #d73a49;">self</span><span class="token">]</span><span class="token">)</span><span class="token">.</span><span class="token">textColor</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> .</span><span class="token">red</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-759"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-757">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-758'
	>
	It’s possible to use appearance proxy on most of the element properties, but what if you wanted to do something like this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-761"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">AppButton.</span><span class="token">appearance(</span><span class="token">)</span><span class="token">.</span><span class="token">cornerRadius</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">12</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-764"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-762">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-763'
	>
	The problem you will encounter is that <code>UIButton</code> does not have a property named <code>cornerRadius</code> that conforms to <code>UIAppearance</code> protocol. Let’s fix that as well!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-767"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-765">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-766'
	>
	In order to add that support, create <code>@objc dynamic</code> computed property:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-769"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">class AppButton</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UIButton </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">@objc</span><span class="token"> </span><span class="token" style="color: #d73a49;">dynamic</span><span class="token"> </span><span class="token">var cornerRadius:</span><span class="token"> CGFloat </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> layer.</span><span class="token">cornerRadius</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">set</span><span class="token"> </span><span class="token">(</span><span class="token">newValue</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> layer.</span><span class="token">cornerRadius</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> newValue </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-772"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-770">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-771'
	>
	That’s it! With this powerful OS feature, you will be one step closer to a colorful app.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-775"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-773">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-774'
	>
	Before continuing to the <code>Protocol</code> part, there is one small thing to consider regarding <code>UIAppearance</code>. As you can see, there isn’t a created <code>extension</code> on <code>UIButton</code> but a custom subclass <code>AppButton</code> instead.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-780"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-776">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-777'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-778'
	>
	Even when it’s possible to use directly UIAppearance on UIButton, it is a good practice to subclass every element which should be themeable.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-783"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-781">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-782'
	>
	The reason for doing that is so you can use <code>UIButton</code> later as the component with default appearance, as well as easily see which component is themeable in code and be sure that your coloring will not interfere with other system components used by the iOS.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-786"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-784">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-785'
	>
	<strong>Protocol, enum and manager</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-789"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-787">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-788'
	>
	The second part of this feature contains a simple enum, two protocols, and one manager to glue everything together.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-792"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-790">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-791'
	>
	<li>Enum</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-795"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-793">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-794'
	>
	Enum has two responsibilities – to list all of the available themes and to provide the configuration for the selected theme.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-797"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">enum Theme</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">case</span><span class="token"> </span><span class="token">red
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">case</span><span class="token"> </span><span class="token">green
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">case</span><span class="token"> </span><span class="token">blue
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Theme</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var appTheme:</span><span class="token"> ThemeProtocol </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">switch</span><span class="token"> </span><span class="token" style="color: #005cc5;">self</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">case</span><span class="token"> .</span><span class="token">red</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">RedTheme(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">case</span><span class="token"> .</span><span class="token">green</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">GreenTheme(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">case</span><span class="token"> .</span><span class="token">blue</span><span class="token" style="color: #d73a49;">:</span><span class="token"> </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">BlueTheme(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-800"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-798">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-799'
	>
	<li>Protocols</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-803"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-801">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-802'
	>
	In general, only one protocol is enough in order for this to work, but let’s separate the responsibility in two protocols. Main <code>ThemeProtocol</code> and <code>Themeable</code> as a helper protocol.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-806"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-804">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-805'
	>
	<em><code>ThemeProtocol</code></em> is used as the main protocol responsible for defining the behaviour of main assets and extension:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-808"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">protocol ThemeProtocol</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var assets:</span><span class="token"> Themeable </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var </span><span class="token" style="color: #d73a49;">`</span><span class="token">extension`:</span><span class="token"> </span><span class="token">(</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">Void</span><span class="token">)</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-811"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-809">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-810'
	>
	This protocol is used later in the last component — manager. But inside of it we can see another <code>Themeable</code> protocol responsible for describing how the item should look.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-814"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-812">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-813'
	>
	If there is a theme which conforms to <code>Themeable</code> and you would like to extend functionality only for that one theme, use <code>extension</code> block in order to extend features only for that one theme.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-819"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-815">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-816'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-817'
	>
	Themeable is the main protocol in this case since item description is defined in it.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-821"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">protocol Themeable</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var labelAssets:</span><span class="token"> LabelAssets </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var buttonAssets:</span><span class="token"> ButtonAssets </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var switchAssets:</span><span class="token"> SwitchAssets </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> ...</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-824"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-822">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-823'
	>
	E.g. description of the one item could look something like this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-826"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">struct LabelAssets</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var textColor:</span><span class="token"> UIColor </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">get</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-829"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-827">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-828'
	>
	<li>Manager</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-832"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-830">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-831'
	>
	The last component here is <code>ThemeManager</code> that binds everything together. All the logic needed to apply the selected theme can be written in just a few lines of code:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-834"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">struct ThemeManager</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">static</span><span class="token"> </span><span class="token">func apply</span><span class="token">(</span><span class="token">_ theme</span><span class="token">: </span><span class="token">Theme</span><span class="token">, </span><span class="token">application</span><span class="token">: </span><span class="token">UIApplication</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> 1</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">let</span><span class="token"> appTheme </span><span class="token" style="color: #d73a49;">=</span><span class="token"> theme.</span><span class="token">appTheme</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> 2</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">updateLabel(</span><span class="token">using:</span><span class="token"> appTheme.</span><span class="token">assets</span><span class="token">.</span><span class="token">labelAssets</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> 3</span><span class="token">
</span></span><span class="line"><span class="token">        appTheme.</span><span class="token">extension</span><span class="token" style="color: #d73a49;">?</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> 4</span><span class="token">
</span></span><span class="line"><span class="token">        application.</span><span class="token">keyWindow</span><span class="token" style="color: #d73a49;">?</span><span class="token">.</span><span class="token">reload(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-837"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-835">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-836'
	>
	Let’s go through those four lines of code one by one, in order to make everything clear. In <code>// 1</code> first line, you are just retrieving items descriptions for the selected theme.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-840"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-838">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-839'
	>
	The second line <code>// 2</code> is responsible for applying that theme using <code>UIAppearance</code> protocol described in the first part. This will only set the new value for our label, but it will not change it yet. Implementation of <code>updateLabel</code> is simple as well:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-842"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">func updateLabel</span><span class="token">(</span><span class="token">using themeAssets</span><span class="token">: </span><span class="token">LabelAssets</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    AppLabel.</span><span class="token">appearance(</span><span class="token">)</span><span class="token">.</span><span class="token">textColor</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> themeAssets.</span><span class="token">textColor</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-845"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-843">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-844'
	>
	In the next line <code>// 3</code> apply some additional changes specific for the theme that implements the <code>extension</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-848"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-846">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-847'
	>
	Let’s say the <em>Blue theme</em> is doing something extra that red and green are not doing (here is shown the implementation of only a blue theme, but the same principle is applied on other themes as well):</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-850"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">class BlueTheme</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ThemeProtocol </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">var assets:</span><span class="token"> Themeable </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">ThemeAssets(</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">labelAssets:</span><span class="token"> </span><span class="token">AppLabelAssets(</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">color:</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">primary</span><span class="token">,
</span></span><span class="line"><span class="token">                </span><span class="token">font:</span><span class="token"> .</span><span class="token">systemFont(</span><span class="token">ofSize:</span><span class="token"> </span><span class="token" style="color: #005cc5;">18</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">)</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">buttonAssets:</span><span class="token"> </span><span class="token">AppButtonAssets(</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">normalBackgroundColor:</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">primary</span><span class="token">,
</span></span><span class="line"><span class="token">                </span><span class="token">selectedBackgroundColor:</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">secondary</span><span class="token">,
</span></span><span class="line"><span class="token">                </span><span class="token">disabledBackgroundColor:</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">tertiary</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">)</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">switchAssets:</span><span class="token"> </span><span class="token">AppSwitchAssets(</span><span class="token">
</span></span><span class="line"><span class="token">                </span><span class="token">isOnColor:</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">primary</span><span class="token">,
</span></span><span class="line"><span class="token">                </span><span class="token">isOnDefault:</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">)</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">cellAssets:</span><span class="token"> </span><span class="token">AppTableViewCellAssets(</span><span class="token">selectedColor:</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">tertiary</span><span class="token">)</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">segmentedControlAssets:</span><span class="token"> </span><span class="token">AppSegmentControllAssets(</span><span class="token">activeColor:</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">primary</span><span class="token">)</span><span class="token">,
</span></span><span class="line"><span class="token">            </span><span class="token">pinAssets:</span><span class="token"> </span><span class="token">AppAnnotationViewAssets(</span><span class="token">color:</span><span class="token"> UIColor.</span><span class="token">blue</span><span class="token">.</span><span class="token">primary</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">var </span><span class="token" style="color: #d73a49;">`</span><span class="token">extension`:</span><span class="token"> </span><span class="token">(</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">-&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">Void</span><span class="token">)</span><span class="token" style="color: #d73a49;">?</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">let</span><span class="token"> proxy </span><span class="token" style="color: #d73a49;">=</span><span class="token"> AppButton.</span><span class="token">appearance(</span><span class="token">whenContainedInInstancesOf:</span><span class="token"> [AppView.</span><span class="token" style="color: #d73a49;">self</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            proxy.</span><span class="token">cornerRadius</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">12.0</span><span class="token">
</span></span><span class="line"><span class="token">            proxy.</span><span class="token">setBackgroundColor(</span><span class="token">color:</span><span class="token"> blue</span><span class="token">, </span><span class="token">forState:</span><span class="token"> .</span><span class="token">normal</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-853"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-851">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-852'
	>
	Last <code>// 4</code> step is to force UI to apply these values to all components and the easiest way is to just reload everything in a window hierarchy:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-855"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> application.keyWindow?.reload()</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> Implementation</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">public</span><span class="token"> </span><span class="token" style="color: #d73a49;">extension</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UIWindow</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Unload all views and add them back</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">///</span><span class="token" style="color: #6a737d;"> Used for applying `UIAppearance` changes to existing views</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">func reload</span><span class="token">(</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        subviews.</span><span class="token" style="color: #005cc5;">forEach</span><span class="token"> </span><span class="token">{</span><span class="token"> view </span><span class="token" style="color: #d73a49;">in</span><span class="token">
</span></span><span class="line"><span class="token">            view.</span><span class="token">removeFromSuperview(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">addSubview(</span><span class="token">view</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">   
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-858"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-856">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-857'
	>
	When tested, this approach did not have any big impact on CPU/GPU and it worked nicely with auto layout (all constraints were intact).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-861"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-859">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-860'
	>
	Applying the theme</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-864"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-862">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-863'
	>
	To change the theme, call one line of code and the entire magic will happen.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-866"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-swift github-light" data-language="swift" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">ThemeManager.</span><span class="token">apply(</span><span class="token">.</span><span class="token">red</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-869"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-867">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-868'
	>
	The red theme will be applied on all screens in the app, without the need to add any kind of code for theme handling inside any view controllers or connect your UI with the code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-872"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-870">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-871'
	>
	Now, if you set your label as <code>AppLabel</code>, even added from the <code>Storyboard</code>, a new color will always be properly applied.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-875"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-873">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-874'
	>
	Color your apps away</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-878"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-876">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-877'
	>
	These were four different ways to implement app customization and make apps dynamically colorful. To make your life easier, avoid using the first two and make apps colorful with the other two methods.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-881"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-879">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-880'
	>
	Use the power of Apple’s <code>UIAppearance</code> for setting the new appearance of an element in combination with <code>Protocols</code> for describing that appearance and applying it. This way, you can create customizable items only once.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-884"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-882">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-883'
	>
	By using them anywhere in the app, you have support for changing themes without the need to add any additional logic for changing its appearance when the theme is changed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-887"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-885">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-886'
	>
	Now that you’ve got this in black and white, your app can finally show its true colors.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/implementing-dynamic-color-themes-in-your-ios-app/">Implementing Dynamic Color Themes in Your iOS App</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>