<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ mobile - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ mobile - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 09 Jun 2026 10:25:45 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/mobile/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Improve Your Phone’s Privacy ]]>
                </title>
                <description>
                    <![CDATA[ We use our phones for everything  –  texting, banking, browsing, tracking our health, even unlocking our homes. But with all that convenience comes a lot of risk. Apps are hungry for your data. Hackers are always looking for cracks in your security. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-improve-your-phones-privacy/</link>
                <guid isPermaLink="false">684c50b9c6ec6bf605276b54</guid>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ privacy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Fri, 13 Jun 2025 16:24:25 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749831817564/98cdcb42-6e7f-49c3-9a7c-49e8db78fc3f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>We use our phones for everything  –  texting, banking, browsing, tracking our health, even unlocking our homes. But with all that convenience comes a lot of risk.</p>
<p>Apps are hungry for your data. Hackers are always looking for cracks in your security. And sometimes, we accidentally give away more than we realize.</p>
<p>The good news is you don’t need to be an expert to tighten things up. </p>
<p>Here are seven simple changes that can seriously improve your phone’s privacy. Each one takes just a few minutes, and together, they make your phone much harder to track, hack, or snoop on.</p>
<h2 id="heading-control-what-tracks-your-location"><strong>Control What Tracks Your Location</strong></h2>
<p>Let’s start with location tracking. </p>
<p>Most people don’t realize how many apps can access their exact whereabouts. Even seemingly harmless apps like weather or games may collect this info in the background. </p>
<p>Some use it to target ads, others sell it to data brokers, and a few could open doors to more serious threats, like someone building a full profile of your movements.</p>
<p>To reduce the risk, go into your phone’s settings and <a target="_blank" href="https://www.avg.com/en/signal/prevent-your-phone-being-tracked">check which apps can access your location</a>. Both iPhone and Android let you limit access to “While Using” the app, instead of “Always.” This way, apps can’t track you silently in the background. </p>
<p>Also, turn off “Precise Location” for apps that don’t need it. Your phone will still know your city, but it won’t pinpoint your exact house. This one tweak keeps dozens of apps from silently tracking your every move.</p>
<h2 id="heading-make-your-passcode-stronger"><strong>Make Your Passcode Stronger</strong></h2>
<p>Next up is your passcode. It’s your phone’s first line of defense, but far too many people still use weak ones  –  like birthdays, 123456, or just swiping a simple pattern. </p>
<p>If someone grabs your phone, a weak passcode makes it much easier for them to get in, especially if they’ve watched you unlock it a few times.</p>
<p>Switch to at least a six-digit PIN or, even better, an alphanumeric passcode with letters and numbers. Yes, it takes a second longer to type, but it’s far harder to guess. </p>
<p>And if your phone supports it, use your fingerprint for unlocking instead of facial recognition. Face unlock can sometimes be fooled by photos or similar faces, while fingerprints are generally more secure.</p>
<p>You should also consider enabling a setting that erases your data after multiple failed login attempts. This way, if your phone falls into the wrong hands, it won’t just be sitting there, waiting to be cracked.</p>
<h2 id="heading-cut-back-unnecessary-app-permissions"><strong>Cut Back Unnecessary App Permissions</strong></h2>
<p>Many apps ask for permissions they don’t really need. </p>
<p>A flashlight app that wants access to your contacts? A calendar app asking for microphone access? These are red flags. </p>
<p>The more permissions you grant, the more ways your data can leak  –  sometimes to advertisers, other times to third parties you’ve never heard of.</p>
<p>Go through your app permissions and turn off access that doesn’t make sense. Does that casual game really need your location? Does a recipe app need to see your photos? Probably not. This isn’t just about avoiding creepy behavior  –  it’s about reducing the number of ways bad actors can exploit your phone if something goes wrong.</p>
<p>Some malicious apps have been caught using these permissions to record audio, access files, or even track your activity across other apps. A regular permissions check-up can help stop that from happening.</p>
<h2 id="heading-switch-to-esim-for-better-security"><strong>Switch to eSIM for Better Security</strong></h2>
<p>One of the most overlooked privacy upgrades is switching to an <a target="_blank" href="https://saily.com/what-is-esim/">eSIM card</a>. That’s a digital SIM card built into your phone, and it offers real advantages over traditional physical SIM cards. The biggest one is security.</p>
<p>Physical SIM cards can be switched out easily if someone steals your phone. There’s also the risk of SIM swapping  –  where attackers convince your carrier to transfer your number to a different SIM, giving them control of your calls, texts, and even two-factor authentication codes. </p>
<p>With an eSIM, there’s no physical card to remove, and activating or transferring it requires extra authentication through your carrier.</p>
<p>If your phone supports eSIM – and most modern iPhones, Pixels, and Galaxy devices do –  you can switch by contacting your mobile carrier or using their app. </p>
<p>Once your eSIM is set up, consider removing the physical SIM entirely. It’s one less way someone can try to hijack your phone number.</p>
<h2 id="heading-dont-leave-bluetooth-and-wifi-open"><strong>Don’t Leave Bluetooth and Wi‑Fi Open</strong></h2>
<p>You might not think twice about leaving Bluetooth or Wi-Fi turned on, but doing so can leave your phone exposed. </p>
<p>Even when you’re not actively connected, your phone continues to look for known networks or nearby devices. This “sniffing” can give away your location, expose your device to tracking, or even let attackers try to exploit unpatched vulnerabilities.</p>
<p>For instance, there have been real-world attacks like <a target="_blank" href="https://en.wikipedia.org/wiki/BlueBorne_%28security_vulnerability%29">BlueBorne</a>, which let hackers take over phones just by being nearby with Bluetooth turned on. </p>
<p>Another risk is “Wi-Fi spoofing” –  when someone sets up a fake public network to trick your phone into connecting, giving them access to your traffic.</p>
<p>To protect yourself, get into the habit of turning off Wi-Fi and Bluetooth when you’re not using them. You’ll save battery, too. </p>
<p>If you’re connecting to public networks, avoid auto-connect settings and tell your phone to “forget” the network afterward. This keeps it from reconnecting without your knowledge later.</p>
<h2 id="heading-use-encrypted-messaging-apps"><strong>Use Encrypted Messaging Apps</strong></h2>
<p>Plain old text messages are easy to intercept. Phone carriers can access them, and if someone manages to snoop on your network, they can read your texts without much effort. That’s why encrypted messaging apps matter.</p>
<p><a target="_blank" href="https://signal.org/#signal">Signal</a> is one of the best options out there. It uses end-to-end encryption, which means only you and the person you’re chatting with can read your messages. Not even the app company can see them. It’s also open-source, which means experts can inspect the code for flaws.</p>
<p>WhatsApp also uses strong encryption, but it’s owned by Meta (formerly Facebook), which has a spottier track record when it comes to data privacy. </p>
<p>If you’re serious about protecting private conversations  –  especially with family, coworkers, or anyone handling sensitive info  – make the switch to an encrypted app.</p>
<h2 id="heading-keep-your-software-updated"><strong>Keep Your Software Updated</strong></h2>
<p>The last one is simple, but often ignored: keep your phone and apps updated. Every update includes security patches that fix known issues. </p>
<p>Hackers and malware often target devices running old software because those bugs are public knowledge by the time they strike. If your phone isn’t set to update automatically, change that now. </p>
<p>Also check your app updates regularly. Some apps introduce new permissions or bugs, so keeping everything current helps close those holes before they can be used against you.</p>
<p>Phones with outdated operating systems are more vulnerable to spyware, data theft, and unauthorized access. So even if you’re not excited about the new features, updates are your silent protectors behind the scenes.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>None of these steps will make you invisible –  but they will make your phone a lot harder to compromise. That’s the goal. Privacy isn’t about locking everything down forever. It’s about knowing what you’re sharing, and taking steps to control it.</p>
<p>Hope you enjoyed this article. You can <a target="_blank" href="https://manishshivanandhan.com/">learn more about me</a> or <a target="_blank" href="https://www.linkedin.com/in/manishmshiva/">connect with me on Linkedidn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The freeCodeCamp Mobile App – Learn to Code Right On Your Phone ]]>
                </title>
                <description>
                    <![CDATA[ I am happy to announce that the freeCodeCamp mobile app is finally ready for you to download. 🎊 The mobile development team just pushed a big update with many helpful improvements, including the much-awaited /learn user experience. You can now code ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/freecodecamp-mobile-app-curriculum-update/</link>
                <guid isPermaLink="false">66adef131ecaa5001d700509</guid>
                
                    <category>
                        <![CDATA[ freeCodeCamp Curriculum ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Android ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sem Bauke ]]>
                </dc:creator>
                <pubDate>Wed, 22 Mar 2023 12:23:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/michal-soukup-hDOskFirs-c-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I am happy to announce that the freeCodeCamp mobile app is finally ready for you to download. 🎊</p>
<p>The mobile development team just pushed a big update with many helpful improvements, including the much-awaited /learn user experience.</p>
<p>You can now code your way through the Responsive Web Design curriculum and save your progress – right on your phone. You can seamlessly shift your freeCodeCamp learning from your desktop to your phone at any time.</p>
<p>And we're working on implementing even more certifications, including our JavaScript Algorithms and Data Structures certification.</p>
<p>The /learn experience features a built-in code editor specifically designed for easy coding on the go. You can also use it to build your certification projects.</p>
<p>Here's a sneak peek into the /learn experience on a mobile device:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-17-at-09.12.10.png" alt="Image" width="600" height="400" loading="lazy">
<em>A view of the instructions pane telling the user how to complete the challenge</em></p>
<p>It's also possible to preview your challenges and projects. This shows a preview of the Camper Café project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-17-at-09.20.16.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Of course, there are so many more tutorials and features to explore in the mobile app. But we'll leave those for you to discover. 😉</p>
<p>We've also made some improvements to /news, Code Radio, and our Podcast listener – which are also available in the app.</p>
<h2 id="heading-how-can-i-download-the-app">How can I download the app?</h2>
<p>You can <a target="_blank" href="https://play.google.com/store/apps/details?id=org.freecodecamp">visit the Play Store page</a> and download the official freeCodeCamp app.</p>
<p>If you are not able to access the Google Play Store in your country, you can download the latest version of the .apk file directly <a target="_blank" href="https://github.com/freeCodeCamp/mobile/releases/latest">from GitHub</a>.</p>
<p>Many of the reviews of the app are of the old 2021 version, which was just a simple web app version that had lots of bugs. </p>
<p>This new version is the result of thousands of hours of development by the freeCodeCamp engineering team. We are very proud of this powerful Flutter-based Android app.</p>
<p>So after you use it for a while, if you like it and find it to be helpful, be sure to leave a 5-star review. 😉</p>
<h2 id="heading-how-can-i-help-the-freecodecamp-community-beta-test-upcoming-features">How can I help the freeCodeCamp community beta test upcoming features?</h2>
<p>Here's how to sign up for the open beta on Android. (We're working on getting the iOS version live soon, too.)</p>
<p>First, <a target="_blank" href="https://play.google.com/store/apps/details?id=org.freecodecamp">visit the Google Play Store page</a>.</p>
<p>At the bottom of the page, there should be a message saying "Join the beta." Just click join, and the app page should show you an update button shortly afterward.</p>
<p>That's it – you are now officially in the beta program. 🧑‍💻</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-88.png" alt="Image" width="600" height="400" loading="lazy">
<em>You may see this message in the Google Play Store.</em></p>
<p>Do note that your progress will not yet be saved on freeCodeCamp's servers. It will only be stored locally on your device. This means that any progress you make will not count towards completing any projects on the freeCodeCamp website. But we're working hard to add this functionality ASAP.</p>
<p>Thank you to all the open source contributors who have helped develop the freeCodeCamp mobile app so far. We are just getting started.</p>
<p>If you are interested in contributing to the mobile app, you can learn a lot about Flutter development and User Experience while helping the community. I encourage you to <a target="_blank" href="https://contribute.freecodecamp.org/#/how-to-setup-freecodecamp-mobile-app-locally">start your contribution journey with this guide</a>.</p>
<p>Happy coding. 🙂</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Monitor Machine Learning Projects on Your Mobile Device📱 ]]>
                </title>
                <description>
                    <![CDATA[ By Rishit Dagli What if you could monitor your Colab, Kaggle, or AzureML Machine Learning projects on your mobile phone? You'd be able to check in on your models on the fly – even while taking a walk🚶.  If you are an ML developer, you know how train... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-monitor-ml-projects-on-mobile-devices/</link>
                <guid isPermaLink="false">66d460cb9208fb118cc6d008</guid>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 24 Aug 2021 19:20:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/08/Frame-4-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rishit Dagli</p>
<p>What if you could monitor your Colab, Kaggle, or AzureML Machine Learning projects on your mobile phone? You'd be able to check in on your models on the fly – even while taking a walk🚶. </p>
<p>If you are an ML developer, you know how training models can easily take a long time. How cool would it be to monitor this from your mobile phones?</p>
<p>Well, you can do it – and in &lt;5 lines of code.</p>
<h2 id="heading-why-monitoring-your-models-remotely-helps">Why Monitoring Your Models Remotely Helps</h2>
<p>Before getting on with the tutorial and showing you how it works, let me briefly describe what you can do with <a target="_blank" href="https://github.com/Rishit-dagli/TF-Watcher">TF Watcher</a>, an open-source project we will use to monitor our ML jobs:</p>
<ul>
<li>Integrates seamlessly with your ML workflow, so you don't need to change any other code in your workflow to make it work</li>
<li>All your visualizations and dashboards are real-time</li>
<li>You probably want to share your live dashboard or a previously run dashboard with your colleagues, and this also allows you to create shareable links</li>
<li>It's a PWA which lets you monitor your models offline in a limited capacity</li>
<li>You also get precise control over when you want to log the metrics</li>
</ul>
<h2 id="heading-how-to-monitor-your-ml-projects-on-your-phone">How to Monitor Your ML Projects on Your Phone</h2>
<p>Let's now go through the tutorial of how to monitor your models on a mobile device with Google Colab. I'll show you how to use tool this in Google Colab, so anyone can try it out, but you can pretty much replicate this anywhere (even on your local machine).</p>
<p>Feel free to follow along with <a target="_blank" href="https://colab.research.google.com/github/Rishit-dagli/TF-Watcher/blob/main/docs/source/TF-Watcher-Quickstart.ipynb">this colab notebook</a>.</p>
<h3 id="heading-install-the-tf-watcher-python-package"><strong>Install the tf-watcher Python Package</strong></h3>
<p>To monitor your Machine Learning jobs on mobile devices, you need to install the <code>tf-watcher</code> Python package. This is an open-source Python package that I built, and you can find the source code in <a target="_blank" href="https://github.com/Rishit-dagli/TF-Watcher">this GitHub repo</a>. </p>
<p>To install the Python package from PyPI, run the following command in your notebook cell:</p>
<pre><code> !pip install tf-watcher
</code></pre><h3 id="heading-how-to-create-a-simple-model">How to Create a Simple Model</h3>
<p>For the purposes of this example, we will see how you can monitor a training job – but you can use this package to monitor your evaluation or prediction jobs too. You will soon also see how you can easily specify the metrics you want to monitor.</p>
<p>In this example, we’ll use the <a target="_blank" href="https://www.tensorflow.org/api_docs/python/tf/keras/datasets/fashion_mnist">Fashion MNIST</a>, a simple dataset of 60,000 grayscale images of 10 fashion categories. We start by loading the dataset and then we'll do some simple preprocessing to further speed up our example.</p>
<p>However, you can use everything we talk about in this article in your more complex experiments.</p>
<p>Let's fetch the dataset:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tensorflow <span class="hljs-keyword">as</span> tf

<span class="hljs-comment"># Load example MNIST data and pre-process it</span>
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

x_train = x_train.reshape(<span class="hljs-number">-1</span>, <span class="hljs-number">784</span>).astype(<span class="hljs-string">"float32"</span>) / <span class="hljs-number">255.0</span>
x_test = x_test.reshape(<span class="hljs-number">-1</span>, <span class="hljs-number">784</span>).astype(<span class="hljs-string">"float32"</span>) / <span class="hljs-number">255.0</span>

<span class="hljs-comment"># Limit the data to 1000 samples to make it faster</span>
x_train = x_train[:<span class="hljs-number">1000</span>]
y_train = y_train[:<span class="hljs-number">1000</span>]
x_test = x_test[:<span class="hljs-number">1000</span>]
y_test = y_test[:<span class="hljs-number">1000</span>]
</code></pre>
<p>Now we'll create a simple neural network that just has a single <code>Dense</code> layer. I'll be showing you how to use this with the TensorFlow's Sequential API, but this works in the exact same way while using the Functional API or subclassed models, too.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Define the Keras model</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_model</span>():</span>
    model = keras.Sequential()
    model.add(keras.layers.Dense(<span class="hljs-number">1</span>, input_dim=<span class="hljs-number">784</span>))
    model.compile(
        optimizer=keras.optimizers.RMSprop(learning_rate=<span class="hljs-number">0.1</span>),
        loss=<span class="hljs-string">"mean_squared_error"</span>,
        metrics=[<span class="hljs-string">"accuracy"</span>],
    )
    <span class="hljs-keyword">return</span> model
</code></pre>
<p>You might have noticed that while compiling our model, we also specified <code>metrics</code> which lets us specify which metrics we need to monitor. </p>
<p>Here I mention "accuracy" so I should be able to monitor accuracy on my mobile device. By default, we logged "loss" so in this case, we would be monitoring 2 metrics: loss and accuracy.</p>
<p>You can add as many metrics as you need. You can also use TensorFlow's <a target="_blank" href="https://www.tensorflow.org/api_docs/python/tf/keras/metrics">built-in metrics</a> or add your own custom metric, too.</p>
<h3 id="heading-how-to-create-an-instance-of-a-callback-class">How to Create an Instance of a Callback Class</h3>
<p>You will now import TF Watcher and create an instance of one of its classes:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tfwatcher

MonitorCallback = tfwatcher.callbacks.EpochEnd(schedule = <span class="hljs-number">1</span>)
</code></pre>
<p>In this example:</p>
<ul>
<li>We use the <code>EpochEnd</code> class from TF Watcher to specify that we are interested in operating in the epoch level. There are quite a few of these classes which you can use for your own needs – find out all about the other classes in <a target="_blank" href="https://rishit-dagli.github.io/TF-Watcher/">the documentation</a>. </li>
<li>We pass in <code>schedule</code> as 1 to monitor after every 1 epoch. You could pass in 3 instead (to monitor after every 3 epochs) or you could also pass in a list of the specific epoch numbers you want to monitor.</li>
</ul>
<p>When you run this piece of code, you should see something like this printed out:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-76.png" alt="Image" width="600" height="400" loading="lazy">
<em>Unique ID for your session</em></p>
<p>This includes a unique 7 character ID for your session. Be sure to make a note of this ID as you will use it to monitor your model.</p>
<h2 id="heading-how-to-start-monitoring-your-model">How to Start Monitoring Your Model 🚀</h2>
<p>Now we will train the model we built and monitor the real-time metrics for training on a mobile device.</p>
<pre><code class="lang-python">model = get_model()

history = model.fit(
    x_train,
    y_train,
    batch_size=<span class="hljs-number">128</span>,
    epochs=<span class="hljs-number">100</span>,
    validation_split=<span class="hljs-number">0.5</span>,
    callbacks = [MonitorCallback]
)
</code></pre>
<p>In this piece of code, we start training our model for 100 epochs (should be pretty quick in this case). We also add the object we made in the earlier step as a <code>callback</code>. </p>
<p>If in your case you are monitoring the prediction instead of training, you would add <code>callbacks = [MonitorCallback]</code> in the predict method.</p>
<p>Once you run the above piece of code, you can start monitoring it from the web app from your mobile device. </p>
<p>Go to <a target="_blank" href="https://www.tfwatcher.tech/">https://www.tfwatcher.tech/</a> and enter the unique ID you created above. This is a PWA which means you can also install this on your mobile devices and use it as a native android app, too.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-80.png" alt="Image" width="600" height="400" loading="lazy">
<em>Install the web app</em></p>
<p>Once you add your session ID you should be able to see your logs progressing in real-time through the charts. Apart from the metrics, you should also be able to see the time it took for each epoch. In other cases this might be time taken for a batch, too.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/TF-Watcher--MLH-Recording.png" alt="Image" width="600" height="400" loading="lazy">
<em>The monitoring dashboard</em></p>
<h3 id="heading-how-to-share-dashboards">How to Share Dashboards</h3>
<p>Since ML is highly collaborative, you might want to share your live dashboards with colleagues. To do so, just click the share link button and the app creates a shareable link for anyone to view your live progress or stored dashboards.</p>
<p><a target="_blank" href="https://www.tfwatcher.tech/logs/ybhzyxK">Here is the shareable link</a> for the dashboard I created in this tutorial.</p>
<h2 id="heading-what-else-can-you-do-with-tf-watcher">What Else Can You Do with TF Watcher?</h2>
<p>Though the example I just showed looked quite cool, there is a lot more we can do with this tool. Now I will briefly talk about two of those scenarios: Distributed Training and non-eager execution.</p>
<h3 id="heading-distributed-training">Distributed Training</h3>
<p>You might often distribute your Machine Learning training across multiple GPUs, multiple machines, or TPUs. You're probably doing this with the <code>[tf.distribute.Strategy](https://www.tensorflow.org/api_docs/python/tf/distribute/Strategy)</code> TensorFlow API. </p>
<p>You can use it in the exact same way with most distribution strategies with limited use while using <code>ParameterServer</code> in a custom training loop.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-79.png" alt="Image" width="600" height="400" loading="lazy">
<em>Distributed training</em></p>
<p>You can find some great examples of how to use these strategies with TensorFlow Keras <a target="_blank" href="https://www.tensorflow.org/guide/distributed_training#examples_and_tutorials">here</a>.</p>
<h3 id="heading-non-eager-execution">Non-eager execution</h3>
<p>In TensorFlow 2, eager execution is turned on by default. But you will often want to use <a target="_blank" href="https://www.tensorflow.org/api_docs/python/tf/function"><code>tf.function</code></a> to make graphs out of your programs. It's a transformation tool that creates Python-independent dataflow graphs out of your Python code.</p>
<p>One of the earliest versions of this project used some Numpy calls but guess what, you can now use the code in the same way in non-eager mode too.</p>
<h2 id="heading-thank-you-for-reading"><strong>Thank you for reading!</strong></h2>
<p>Thank you for sticking with me until the end. You can now monitor your Machine Learning projects from anywhere on your mobile device and take them to the next level. I hope you are as excited to start using this as I was.</p>
<p>If you learned something new or enjoyed reading this article, please share it so that others can see it. Until then, see you in the next post!</p>
<p>You can also find me on Twitter <a target="_blank" href="https://twitter.com/rishit_dagli">@rishit_dagli</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Native Communication Bridge in Flutter with WebView and JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ As a follow up to my article explaining how to create communication bridges in Android and iOS, I thought it might be a good idea to do the same for Flutter. While it may seem like this is a straightforward affair, you’ll soon realize it takes a bit ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-native-communication-bridge-in-flutter-with-webview-and-javascript/</link>
                <guid isPermaLink="false">66ba5008158e6c6a8cb8c79e</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tomer ]]>
                </dc:creator>
                <pubDate>Tue, 01 Dec 2020 16:27:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/0_vBF65VQHbXyUUeHN.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As a follow up to my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-cross-origin-communication-bridges-in-ios-and-andriod-7baef82b3f02/">article</a> explaining how to create communication bridges in Android and iOS, I thought it might be a good idea to do the same for Flutter.</p>
<p>While it may seem like this is a straightforward affair, you’ll soon realize it takes a bit of work to get this functionality working.</p>
<p>First and foremost, it is important to realize that (at the time of writing this article) Flutter does <strong>not</strong> have built in support for embedded WebViews.</p>
<p>Unlike a native application in either Kotlin or Swift where you can just instantiate a WebView component, you cannot add a WebView component to your Flutter application out of the box.</p>
<p>In this article, we'll go over how to configure WebView in Flutter applications, and how to communicate between Flutter and Webview.</p>
<h2 id="heading-how-to-configure-webview-in-a-flutter-application">How to configure WebView in a Flutter application</h2>
<p>After creating a new Flutter project, we need to use the <a target="_blank" href="https://pub.dev/packages/webview_flutter">webview_flutter package</a> to be able to use a WebView. We will add the dependency to our <code>pubspec.yaml</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>  
       <span class="hljs-attr">flutter:</span>    
           <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>
       <span class="hljs-attr">webview_flutter:</span> <span class="hljs-string">^1.0.7</span>
</code></pre>
<p>Then, we need to run <code>pub get</code> in the terminal:</p>
<pre><code class="lang-bash">flutter pub get
</code></pre>
<p>Next, we import the package in our <code>main.dart</code> file:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:webview_flutter/webview_flutter.dart'</span>;
</code></pre>
<p>If you haven’t cleaned up the code from the starter project yet, now is a good time to do so. </p>
<p>After you remove all the comments, the floating action button and everything related to it, you will be left with this (I added a text widget just for show):</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:convert'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:webview_flutter/webview_flutter.dart'</span>;

<span class="hljs-keyword">void</span> main() {
  runApp(MyApp());
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      title: <span class="hljs-string">'Communication Bridge'</span>,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: <span class="hljs-string">'Native - JS Communication Bridge'</span>),
    );
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyHomePage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  MyHomePage({Key key, <span class="hljs-keyword">this</span>.title}) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> title;

  <span class="hljs-meta">@override</span>
  _MyHomePageState createState() =&gt; _MyHomePageState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyHomePage</span>&gt; </span>{

  WebViewController _controller;

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Text(
      <span class="hljs-string">"Flutter JS-Native Communication Bridge"</span>
    );
  }
}
</code></pre>
<p>Which will give you this result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_txc-SxRUBZFMR4mdJq-tCA.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-creating-a-local-html-asset">Creating a local HTML asset</h3>
<p>Since we will be using a local HTML file with embedded JavaScript code inside of it, we need to create it in our project. </p>
<p>All local assets in a Flutter application need to be in an <code>assets</code> directory. </p>
<p>Create an <code>assets</code> directory in your main project hierarchy by right clicking in the left side panel and choosing New → Directory:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_xlBwiAWJUdKiZWDsAdx7SQ.png" alt="Image" width="600" height="400" loading="lazy">
<em>The file hierarchy after creating the asses directory</em></p>
<p>Then, go on ahead and create <code>index.html</code> inside the assets directory and add the following code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Local HTML File<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span>&gt;</span>Hello World!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>&gt;</span><span class="javascript">
            <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fromFlutter</span>(<span class="hljs-params">newTitle</span>) </span>{
                <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"title"</span>).innerHTML = newTitle;
                sendBack();
             }

             <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendBack</span>(<span class="hljs-params"></span>) </span>{
                messageHandler.postMessage(<span class="hljs-string">"Hello from JS"</span>);
             }
        </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>You will notice that we have written two methods in the JavaScript section of our html:</p>
<ol>
<li><code>fromFlutter</code> is the method we will call from Flutter with a string representing the new title for the page</li>
<li><code>sendBack</code> is the method we will call to communicate back to Flutter. In it we are sending a string message.</li>
</ol>
<p>We will get into the contents of sendBack in a minute, but before that, we have to set up our WebView in our application.</p>
<p>✋ Don’t forget to add <code>index.html</code> to your <code>pubspec.yaml</code> under an <code>assets</code> section (use the correct indentation):</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>
  <span class="hljs-attr">flutter:</span>
    <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>
  <span class="hljs-attr">webview_flutter:</span> <span class="hljs-string">^1.0.7</span>
  <span class="hljs-attr">cupertino_icons:</span> <span class="hljs-string">^1.0.0</span>

<span class="hljs-attr">dev_dependencies:</span>
  <span class="hljs-attr">flutter_test:</span>
    <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>

<span class="hljs-attr">flutter:</span>
  <span class="hljs-attr">uses-material-design:</span> <span class="hljs-literal">true</span>

  <span class="hljs-attr">assets:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">assets/index.html</span>
</code></pre>
<h3 id="heading-set-up-the-webview">Set up the WebView</h3>
<p>Since we already imported the package into our <code>main.dart</code> file, we need to replace the Text widget with a WebView widget:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyHomePage</span>&gt; </span>{

  WebViewController _controller;

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(title: Text(<span class="hljs-string">'Webview'</span>)),
      body: WebView(
        initialUrl: <span class="hljs-string">'about:blank'</span>,
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
    );
  }

  _loadHtmlFromAssets() <span class="hljs-keyword">async</span> {
    <span class="hljs-built_in">String</span> file = <span class="hljs-keyword">await</span> rootBundle.loadString(<span class="hljs-string">'assets/index.html'</span>);
    _controller.loadUrl(<span class="hljs-built_in">Uri</span>.dataFromString(
        file,
        mimeType: <span class="hljs-string">'text/html'</span>,
        encoding: Encoding.getByName(<span class="hljs-string">'utf-8'</span>)).toString());
  }

}
</code></pre>
<p>We wrapped our WebView with a Scaffold widget (we'll go over this more later in the article), but let’s focus on the different fields of the WebView widget seen above:</p>
<ul>
<li><code>initialUrl</code> is where we can define which URL the WebView points to. Here we decided to point it to nothing since we are going to load our local HTML file</li>
<li><code>onWebViewCreated</code> is a callback we get from the package once the WebView is created. Since we want to save the controller instance that we get from this callback, we have created a private member to store it to, <code>_controller</code></li>
</ul>
<p>You will also notice that we created a method called <code>_loadHtmlFromAssets</code>, which as is implied by its name, will load our local HTML file into the WebView.</p>
<p>Inside this method, we use our private WebViewController instance, <code>_controller</code>, and it’s exposed method <code>loadUrl</code> to load our local HTML file. Due to the logic in this method, its execution is asynchronous.</p>
<p>If we run our application, we will get the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_hE6jeEprGAW3YkVt0AiYrA.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-communicate-from-flutter-to-webview">How to communicate from Flutter to WebView</h2>
<p>Now let’s add some functionality to call the <code>fromFlutter</code> method we defined in our local HTML file. </p>
<p>To do that, we will be adding a Floating Action Button (or FAB) to our layout and connecting its <code>onPressed</code> method to call the <code>fromFlutter</code> method.</p>
<p>This is also the reason behind the usage of the Scaffold widget – so we can easily add a FAB:</p>
<pre><code class="lang-dart"><span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(title: Text(<span class="hljs-string">'Webview'</span>)),
      body: WebView(
        initialUrl: <span class="hljs-string">'about:blank'</span>,
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: <span class="hljs-keyword">const</span> Icon(Icons.arrow_upward),
        onPressed: () {
          _controller.evaluateJavascript(<span class="hljs-string">'fromFlutter("From Flutter")'</span>);
        },
      ),
    );
  }
</code></pre>
<p>In order to make calls from Flutter to our loaded HTML we are using the <code>evaluateJavascript</code> method. To be able to use it, we must add another property to our WebView called <code>javascriptMode</code>. </p>
<p>In the code above, we are setting it to unrestricted. If we don’t set it, we will not be able to communicate between Flutter and the WebView:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_odgcLrPQUlhGHdbaF4rO4A.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-communicate-back-from-webview-to-flutter">How to communicate back from WebView to Flutter</h2>
<p>Remember how I said we will talk about the contents of our <code>sendBack</code> method? Let's do that now:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendBack</span>(<span class="hljs-params"></span>) </span>{
  messageHandler.postMessage(<span class="hljs-string">"Hello from JS"</span>);
}
</code></pre>
<p>In the <code>sendBack</code> method, we are using an object called <code>messageHandler</code>, and it’s attached method called <code>postMessage</code>. </p>
<p>Just like creating a communication bridge in a native application, once you set one up, you are adding an object to the global <code>Window</code> object in the JavaScript layer to be used for communication.</p>
<p>You can name this object to whatever you like as long as you reference it when you make calls from JavaScript to your native application.</p>
<p>How is this object added to the JavaScript layer in our application, you might ask? By adding the <code>JavascriptChannels</code> attribute to our WebView widget:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyHomePage</span>&gt; </span>{

  WebViewController _controller;
  <span class="hljs-keyword">final</span> GlobalKey&lt;ScaffoldState&gt; _scaffoldKey = <span class="hljs-keyword">new</span> GlobalKey&lt;ScaffoldState&gt;();

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text(<span class="hljs-string">'Webview'</span>)),
      body: WebView(
        initialUrl: <span class="hljs-string">'about:blank'</span>,
        javascriptMode: JavascriptMode.unrestricted,
        javascriptChannels: <span class="hljs-built_in">Set</span>.from([
          JavascriptChannel(
              name: <span class="hljs-string">'messageHandler'</span>,
              onMessageReceived: (JavascriptMessage message) {
               _scaffoldKey.currentState.showSnackBar(
                  SnackBar(
                      content: Text(message)
                  )
                 );
              })
        ]),
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: <span class="hljs-keyword">const</span> Icon(Icons.arrow_upward),
        onPressed: () {
          _controller.evaluateJavascript(<span class="hljs-string">'fromFlutter("From Flutter")'</span>);
        },
      ),
    );

  }
</code></pre>
<p>We have defined a <code>JavascriptChannel</code> with a name and an <code>onMessageReceived</code> handler. The name we have given this channel, <code>messageHandler</code>, is the name we are using to communicate from the local HTML file we loaded to our native layer.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_AGpwDR2o8Fh7Re_Cwtg7fA.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Great success</em></p>
<p>For the keen eyed, you probably noticed that a new private variable has been added, <code>_scaffoldKey</code>. This is because we needed to add a key to our Scaffold widget so we can display the snackbar.</p>
<p>You can get the source code for the application described in this article below:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/TomerPacific/MediumArticles/tree/master/flutter_communication_bridge">https://github.com/TomerPacific/MediumArticles/tree/master/flutter_communication_bridge</a></div>
<p>Two final points to be aware of:</p>
<ol>
<li><a target="_blank" href="https://github.com/flutter/flutter/issues/30358">The alert method is broken in the webview_flutter package</a></li>
<li>To use the package in iOS, you must add the following key to your <code>info.plist</code> file: <code>&lt;key&gt;io.flutter.embedded_views_preview&lt;/key&gt;&lt;string&gt;yes&lt;/string&gt;</code></li>
</ol>
<p>Here are some other sources you may find helpful if you want to learn more about Flutter and WebViews:</p>
<ul>
<li><a target="_blank" href="https://medium.com/flutter/the-power-of-webviews-in-flutter-a56234b57df2">The Power of WebViews In Flutter</a></li>
<li><a target="_blank" href="https://pub.dev/packages/webview_flutter">WebView_Flutter Package</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Mobile App That Outsmarts the Competitors ]]>
                </title>
                <description>
                    <![CDATA[ By Emma Coffinet The amount of time people spend on their mobile phones has increased over the years, and so has the number of people using mobile devices. It’s safe to say that mobile has almost completely taken over the desktop. With the number of ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-mobile-app-that-outsmarts-the-competitors/</link>
                <guid isPermaLink="false">66d45e3e73634435aafcef72</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 21 Jul 2020 12:54:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/image-31-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Emma Coffinet</p>
<p>The amount of time people spend on their mobile phones has increased over the years, and so has the number of people using mobile devices.</p>
<p>It’s safe to say that <a target="_blank" href="https://www.freecodecamp.org/news/the-best-linux-tutorials/">mobile</a> has almost completely taken over the desktop. With the number of users crossing over to mobile, it has become essential to create apps that can provide a seamless and engaging mobile experience.</p>
<p>For a business, there are plenty of ways in which an app can be helpful. Some of these include:</p>
<ul>
<li>Improving sales and revenue generation.</li>
<li>Building a community and increasing engagement by providing the audience with resources.</li>
<li>Improving employee communication with internal business apps.</li>
<li>Improving mobile marketing strategy and increasing brand awareness.</li>
</ul>
<p>Even though there are many positives to it, creating an app can be tedious and intimidating. It can also be costly, risky, and can take a lot of time.</p>
<p>But if you create the app well enough, it will be worth everything in the end. To create a smart mobile app that beats the competition, here are some tips.</p>
<h2 id="heading-define-the-app-objectives">Define the app objectives</h2>
<p>The first step before you even start creating a mobile app is defining your reasons and clearly stating the app’s objectives. </p>
<p>If you don’t have clarity about small details like this, it will affect your planning and app building. In the end, you are not likely to get what you want.</p>
<p>There are two things that you must try to satisfy with your app. First, the ideal goal of users, and second, the purpose of your business. </p>
<p>To determine these, you have to ask yourself specific questions:</p>
<ul>
<li>Which parts of your business do you need to improve?</li>
<li>How can an app help solve the problem?</li>
<li>What are the possible results that you might get?</li>
</ul>
<p>Some other areas of your business that you also have to consider are your budget, timeline, market research, and so on.</p>
<h2 id="heading-state-the-functions-and-features-of-the-app">State the functions and features of the app</h2>
<p>After stating the purpose and objectives of your app clearly, your next step would be to define the <a target="_blank" href="https://mindsea.com/how-to-build-a-mobile-app/">scope of your mobile app</a>. At this point, you start to determine what the app will look like and the features that it will have. </p>
<p>You need to be creative and make a list of necessary functionality and features to achieve your desired results.</p>
<p>Some features that you may include in your app are:</p>
<ul>
<li>eCommerce integrations</li>
<li>Social sharing</li>
<li>Chat</li>
<li>Push notifications</li>
<li>Forms</li>
<li>Contact form</li>
</ul>
<p>Write down all the valuable features and let this guide you through your app development process.</p>
<h2 id="heading-research-app-competition">Research app competition</h2>
<p>Although you already are sure of what you are building and what you need in your app, you might want to look at some of your most successful competitors. Consider what they are doing with their apps and how it is helping them reach similar goals.</p>
<p>Be sure not to look at just your local competition. Research some of the bigger companies in the same industry that reach out to a similar audience in your country or other parts of the world. With this, you can get inspired and get new ideas you can use in the market.</p>
<p>Some of the things that you have to consider are app layout, features, and functionalities. Look out for other things that stand out or things that you might be missing.</p>
<h2 id="heading-plan-the-ux-and-user-journey-of-the-mobile-app">Plan the UX and user journey of the mobile app</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-32.png" alt="Image" width="600" height="400" loading="lazy">
<em>UX of an App</em></p>
<p>The success of <a target="_blank" href="https://buildfire.com/how-to-create-a-mobile-app/">mobile apps</a> depends a lot on the User Experience of the app. You have to make sure that your app’s functions align with the users’ desires and expectations. You must plan your User Experience in advance.</p>
<p>If you don’t plan the app’s user experience, you will not have an idea of how complex the app is. You also will not realize how much time you need to invest in developing the app. In the end, you won’t have something tangible to present during user testing. </p>
<p>Make sure that the users have a low UX resistance with the app. The primary goal here is to ensure that they find the solution in the most efficient and intuitive way possible.</p>
<p>If you don’t take the time to plan the UX before you start to build correctly, your users will likely experience difficulty with their use of the app. Then you would need to spend more resources and time to fix things.</p>
<p>The significant difference between a successful app and an unsuccessful one is the user experience. Poor user experience can stem from making some avoidable mistakes when building the app. Some of the mistakes to avoid for good user experience are:</p>
<h3 id="heading-not-understanding-the-needs-of-the-user">Not understanding the needs of the user</h3>
<p>The very foundation for building a good app is understanding what users need. Having an understanding of your audience is crucial. You have to consider the users’ pain points, how your app is better than your competition, and the interface.</p>
<h3 id="heading-adding-too-many-features">Adding too many features</h3>
<p>If it's your first time <a target="_blank" href="https://www.google.com/url?sa=t&amp;source=web&amp;rct=j&amp;url=https://brainiuminfotech.com/blog/mobile-app-development-small-business-get-right/&amp;ved=2ahUKEwjw4MC04c3qAhWJSsAKHehNDVoQFjAKegQIAhAB&amp;usg=AOvVaw0nk8eCEnSAMUERPZjXcsu7">developing a mobile app</a>, you might be tempted to add a lot of features you think are cool. </p>
<p>But this actually relates to a poor user experience most of the time. These features can overwhelm users and make them ditch your app.</p>
<h3 id="heading-creating-poor-and-confusing-navigation">Creating poor and confusing navigation</h3>
<p>No matter how good the onboarding experience is, if users cannot find what they want easily, then your app is less useful. </p>
<p>Your app should have clear navigation that makes it easy for even first time users to do what they want. There are different types of navigation, so you have to choose what you think is the most intuitive for your app.</p>
<p>Other mistakes that you can make that lead to poor user experience are:</p>
<ul>
<li>Neglecting the experience of first-time users.</li>
<li>Overcrowding the user interface</li>
<li>Using jargon and terminology that users don’t understand.</li>
</ul>
<h2 id="heading-launch-the-app">Launch the app</h2>
<p>The last step to <a target="_blank" href="https://www.appypie.com/how-to-create-an-app">creating a mobile app</a> is to launch the app. Following the launch, you should be open to user feedback and improve the app with regular updates based on user experience.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>It takes a lot of time, effort, and resources to create a mobile app. So if you want to create one that outsmarts the competition, you have to do more. It takes a lot of effort, and we’ve highlighted some of the key things you should do in this article. </p>
<p>Whatever it takes, make sure to put the user experience first. Focus on satisfying them and solving their problems with the app, and you are already halfway there.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What I've Learned On My Journey As A Self-Taught Mobile Developer ]]>
                </title>
                <description>
                    <![CDATA[ By Dragos Ivanov In this post, I'll share my entire journey about how I became a professional mobile developer. I hope that reading about my experience will help you reflect on your present and your future, and will either help you start your career ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/reflections-on-my-journey-as-a-self-taught-mobile-developer/</link>
                <guid isPermaLink="false">66d45e3e246e57ac83a2c72d</guid>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 10 Jul 2020 11:06:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/Self-Taught-Developer-3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dragos Ivanov</p>
<p>In this post, I'll share my entire journey about how I became a professional mobile developer.</p>
<p>I hope that reading about my experience will help you reflect on your present and your future, and will either help you start your career as a developer or motivate you to move forward in achieving your goals.</p>
<h2 id="heading-my-university-degree-and-how-it-all-started">My university degree and how it all started</h2>
<p>I finished high school with a mathematics-informatics degree in a small town in Romania.</p>
<p>Like most of my friends, you had two choices in terms of cities to go to for university. I chose Bucharest, the capital of Romania.</p>
<p>I grew up thinking that university is a mandatory thing. That probably happens in most countries.</p>
<p>All our parents want it for us.</p>
<p>I never felt a desire to choose a specific degree. Sound familiar? Never saw myself working as something after I graduated.</p>
<p>In the end, I chose to go to an economics university in Bucharest. Again there were two options. One was considered a good university, and another where you would pay a lot of money just to get a degree.</p>
<p>I took some exams at the first one, without studying, to be honest. And obviously I did not pass. </p>
<p>I had to go with the second option.</p>
<p>Fast forward and I graduated from my economics university. But I graduated two years late. I never had a passion for economics and never saw myself working as a banker. I always thought I wanted to get the diploma, and that's it.</p>
<p>I never considered how much I paid for that useless degree, but I needed a diploma to be accepted by society, right?</p>
<p>I was a failure, with an economics degree, but no experience or knowledge. In the following years, with the help of my family, I managed to create two businesses that failed, too.</p>
<p>I will not discuss those in the story, but let's just say that I learned a lot. I also played online poker, and I was pretty good at it.</p>
<p>Seven years after graduating from high school I found myself with no job experience, no successful business, and no money.</p>
<p>I knew I had to take action, and I knew that all my dreams about having a successful business would not happen soon unless I had a backup plan.</p>
<p>That's when I thought: </p>
<p><em>What job can I get that will make me happy, pay me well, and allow me to have a good life at 30 - 40 years old, even if I never manage to create my own business?</em></p>
<p>The only answer that came to mind was programming. I had some prior experience in high school and built a few websites.</p>
<p>There was only one problem – I did not like mathematics in high school, and I always thought that I would not be able to learn professional programming without an excellent understanding of it.</p>
<p>I was wrong.</p>
<p>There are probably a lot of people like me, people who have the same thoughts and doubts. But all you have to do is take action and start learning.</p>
<h2 id="heading-learning-android-and-java">Learning Android and Java</h2>
<p>It was 2014 when I first started looking into the idea to learn to code.</p>
<p>First thing I did was to Google for some courses in Bucharest, and I found a company that invited me to their offices. I went there, and I remember they had a lovely furnished office with a lot of iMACs. I told myself, "That's what I need."</p>
<p>Ten minutes later I found that they were doing all their courses online and that it was more like an office to sell the course rather than do the course.</p>
<p>I don't remember the exact price, but it was around 1500 - 2000 USD. I didn't take it.</p>
<p>I let go of the idea for a few months, then 2015 came. New year, new plans, new life, you know?</p>
<p>I started to look into an in person course again, and found out that they were called bootcamps.</p>
<p>Discovered one in Bucharest and they were doing Java, and it only cost around 800 USD for four months. It would be a few hours a day with a teacher and other students.</p>
<p>Looking back, I think they were cheap for what they offered, but I think we were the second batch they had. </p>
<p>They were telling us all kinds of things about being hired after the bootcamp, but I did not care. </p>
<p>I wanted to learn to code, and I thought that I would manage to find a job quickly after just a few months. I was right, but it was not as easy as I thought.</p>
<p>The classes started. They always told us that it is not enough to do only lessons during our hours together.</p>
<p>I tried to listen. But at home, things never made sense. Programming was hard, and I often thought that I would not be able to finish the bootcamp.</p>
<p>I pushed myself harder and harder. It was one month into the courses when I found that we were going to learn Java with Android, but again, I did not care. I was falling in love with Eclipse and things happened on the screen as we coded.</p>
<p>Eclipse is an Integrated Development Environment that was originally used to develop for Android. Now we use Android Studio.</p>
<p>It was hard. Lesson after lesson I was trying to learn variables, classes, inheritance, encapsulation, for loops, and so on. </p>
<p>But I struggled. I didn't have a clear picture of how I could use all these in a bigger app. It did not make sense a lot of times.</p>
<p>If you just started programming and you feel the same, I want you to know that it's normal.</p>
<p>Our mentors always told us: "You do not have to know all these off top of your head. Just try to understand what they are and how you can use them."</p>
<p>They were right, but I found that out later. At that specific moment in time, it did not help.</p>
<p>One thing which I regret is that I did not do projects from the beginning. I always thought that I needed a teacher and that you cannot learn anything online on your own. I was lazy and again, wrong.</p>
<p>After four months, I managed to make my first "non-working" app. It was an app where students could rent rooms from other students or people.</p>
<p>I said "non-working" because it did not have any backend or any users. It was more like a demo app that was using some SQLite for storing data.</p>
<p>I was proud of it, because a few months before, I never imagined I could do it.</p>
<p>The bootcamp finished, and I don't think I ever spoke with anyone from their management again.</p>
<p>Not sure if they tried to get me a job, or maybe they thought I was not good enough for a career as a developer.</p>
<h2 id="heading-first-interviews-and-first-job-as-a-junior-android-developer">First interviews and first job as a Junior Android Developer</h2>
<p>I started interviewing, and I remember that my first one was for a Java role at a big international company located in Bucharest. (Hint: they have over 300,000 employees, and their revenue from 2019 was about 77 billion.)</p>
<p>I did not take the interview, but I think that the conversation was a good one. I probably wasn't hired because I didn't have any experience.</p>
<p>After that, it took me another month to get the next interview.</p>
<p>A friend I made in the bootcamp helped by recommending me. If he reads this post, I want to thank him.</p>
<p>The role was actually as an Android developer for a Romanian outsourcing company that had a contract with a telecom company.</p>
<p>I had two interviews with them, mostly technical questions, and I still remember when they called to offer the role.</p>
<p>The salary was small, but it did not matter.</p>
<p>I think I started the bootcamp at the end of May 2015, and I began my first role as Junior Android Developer in January 2016.</p>
<p>It was quite an achievement.</p>
<p>My manager assigned me a project, and then I started learning about version control and how to work Agile, and how to work in 2 weeks sprints.</p>
<p>If you've started learning programming or you want to start, I recommend three things.</p>
<ul>
<li>Start today (Optional if you already started)</li>
<li>Do as many projects as possible</li>
<li>Learn version control (Git, Bitbucket, or Gitlab) and push all your projects there.</li>
</ul>
<p>Maybe I will write another article about all these things.</p>
<p>During my time at that company, I met a lot of friendly and helpful people. I was probably annoying to a lot of them because, at the beginning, I was asking for a lot of help.</p>
<h2 id="heading-new-country-and-more-android-jobs">New country and more Android jobs</h2>
<p>9 Months later I decided that I wanted to move to London because I was getting a lot of messages from recruiters. Also I thought that it would be easier to further my career there, then return to Bucharest.</p>
<p>I was lucky that my sister lived there, and she was kind enough to let me live with her.</p>
<p>Even when I had recruiters promising me interviews and stuff like that, when I got there I had zero meetings.</p>
<p>I knew that it would not be easy, and I applied to a lot of jobs online.</p>
<p>After two weeks, I got an interview at a British Telecom services company. They had a small IT department, and their Android developer was leaving. They had internal Android CRMs apps, used by their employees, and they needed someone for maintenance and to develop new apps.</p>
<p>It was a one year contract, and the pay wasn't great (I found that out later), but again, I was happy.</p>
<p>I learned a ton in that year (on my own).</p>
<p>I learned Android specific technologies like:</p>
<ul>
<li>What's an architecture like Model-View-Presenter and how to use it in an app</li>
<li>How to do proper Unit Testing</li>
<li>The SOLID principles</li>
</ul>
<p>And so on.</p>
<p>I learned all that at work and in my free time. I was working, and in my spare time, I was building apps for myself.</p>
<p>To this day, all my apps (5 on Android) have more than 100k downloads, mostly organic, but only one of them made more than 2,000 USD.</p>
<p>I worked for the telecom company for precisely one year. I wanted to try something different thing in London and work with more Android developers.</p>
<p>It took me some time to understand that, as a software developer, you always have to do more than what you do at work. It's the same with doctors or lawyers. They regularly need to improve their knowledge to be better than others.</p>
<p>I felt ready to work on a more significant project, but I don't think I was skilled enough.</p>
<p>It did not discourage me, and I took an Android role at a global outsourcing company.</p>
<p>I was going to work for a big British bank in London.</p>
<p>I was scared initially, but it took me one month to feel like I was part of that project.</p>
<p>I did three interviews before I entered the project. </p>
<p>During my career, all the interviews I did had two or three steps.</p>
<p>The first one is usually with HR where they ask you things about your experience.</p>
<p>The second interview could be with technical questions, take-home assignments or technical questions with some algorithms.</p>
<p>The third interview might be with a tech lead or with a manager or again with someone from HR.   </p>
<p>I started working at the bank in a proper Scrum team. We were 4 Android devs, 4 iOS devs, a Project Manager, a Product Owner, 2-3 Quality Assurance Engineers, a Business Analyst, Copywriter, Designers. </p>
<p>All these people were developing a crucial part of the app. The project was massive.</p>
<p>Just in the development team there were more than 30 Android and more than 30 iOS developers.</p>
<p>I stayed at that role for one year, like with my previous job. The reason? I wanted to go back to Romania.</p>
<p>I was lucky enough to have only good colleagues around me. </p>
<p>It's never wrong to ask for help if you want to learn. We've all started from the beginning, with zero knowledge. I feel that it's terrible not to want to learn when you don't know.</p>
<p>The year at the bank taught me a lot, and it felt like a few years. I learned:</p>
<ul>
<li>How to do code reviews</li>
<li>How to work on a project that required 100% code coverage for Unit Testing</li>
<li>How to deliver features on time</li>
<li>What is clean architecture and how to write code that's easy to read without leaving a ton of comments</li>
</ul>
<p>And many more that I probably don't remember.</p>
<h2 id="heading-going-back-home-with-more-knowledge">Going back home with more knowledge</h2>
<p>It was November 2018 when I went back to Bucharest, after two years and a bit of living in London.</p>
<p>It was an excellent experience, but it did not feel like home.</p>
<p>I got a new job for another outsourcing Romanian company quite fast (2 weeks) after I came back. </p>
<p>It took me only four months to leave again for a new six months project in London.</p>
<p>I was not happy to leave my girlfriend alone, but the money was good for only six months of work.</p>
<p>I'm not allowed to disclose any information about the project because I signed a non-disclosure agreement, and today I'm still working for them. But I'm located in Bucharest right now. I've been working for the current company for more than a year and a half.</p>
<p>What did I learn on this project?</p>
<ul>
<li>How to create a team</li>
<li>How to start a big app from scratch. I will probably be very proud once we launch and people will use it.</li>
<li>How to adapt requirements with a lot of unknowns.</li>
<li>How to deliver by working with people all over the world.</li>
</ul>
<p>It's been a crazy journey.</p>
<h2 id="heading-conclusion-and-what-i-learned">Conclusion and what I learned</h2>
<p>My post is at over 2000 words, and I feel I did not give you a lot of details about what I learned. I only scratched the surface.</p>
<p>It was not easy, but I don't regret choosing this career.</p>
<p>If you are me from 5 years ago, just start. </p>
<p>You will feel like quitting. You will think that you are not smart enough, you will feel like any developer that takes a few hours/days to solve something without any luck and then has a moment of brilliance.</p>
<p>It's not wrong not to know, and no question is stupid. It's terrible if you don't want to learn.</p>
<p>Today, more developers than ever are willing to help. You can easily find Discord groups where people are happy to answer your programming questions. There are a lot of Reddit communities that will be helpful. Maybe even Slack channels can work for you. Finding a mentor can be a solution too.</p>
<p>Websites and YouTube channels like freeCodeCamp are all you need to get started.</p>
<p>Here are all the things I hope you learned in this post:</p>
<ul>
<li>Starting is hard, but every day of learning something new will give you enormous satisfaction.</li>
<li>You need to do all kinds of projects. Knowing the basics is good, but building things and working with version control will help you prepare for a future job.</li>
<li>People are willing to help (both online and future colleagues)</li>
<li>There will be days when nothing will work. You will not find a solution easily. Either relax and come back to the problem later or just ask for help.</li>
<li>All developers (junior, mid or senior) search for solutions on Google and get stuck frequently.</li>
<li>You will feel impostor syndrome, but trust me when I say that I met developers with CS degrees who are worse than me.</li>
<li>Being a developer it’s not only about coding. Soft skills are important too.</li>
</ul>
<p>If you liked this article and want more of this, please <a target="_blank" href="https://twitter.com/dragos_ivanov">follow me on Twitter</a>. I write about my journey as a mobile developer, my failed/successful start-ups, about app marketing, and all kinds of other things I learned in the past 10 years.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Develop Particle IoT Apps Using NativeScript ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff If you're developing any type of IoT product, inevitably you'll need some type of mobile app. While there are easy ways, they're not for production use. In this tutorial, we'll talk about the basics of Particle app development. You'll ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-develop-particle-iot-apps-using-nativescript/</link>
                <guid isPermaLink="false">66d8504f29e30bc0ad47757b</guid>
                
                    <category>
                        <![CDATA[ iot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ NativeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ particle ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 27 Jan 2020 17:42:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/01/NativeScript---Particle.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p>If you're developing any type of IoT product, inevitably you'll need some type of mobile app. While <a target="_blank" href="https://www.jaredwolff.com/create-a-cross-platform-app-using-blynk/">there are easy ways</a>, they're not for production use.</p>
<p>In this tutorial, we'll talk about the basics of Particle app development. You'll learn about some of the many app frameworks you can take advantage of. Plus there's libraries, tricks, and tools along the way to make your life a lot easier.</p>
<h2 id="heading-app-frameworks">App Frameworks</h2>
<p>Sometimes it's dang near irritating to program multiple applications natively. You see, Swift (or Objective C ?) and Java aren't terrible at first glance (well, maybe except for Obj-C ?). But when you're resource constrained, you have to figure out a new game plan. That's where App Frameworks come in.</p>
<p>These frameworks allow an app developer to write, build and test cross platform apps. In some cases, the frameworks convert your app into native code. That means that they run as fast and as well as one written in Swift or Java.</p>
<p>I did the research and as of January 2020, here are some of the most supported frameworks:</p>
<ul>
<li><a target="_blank" href="https://github.com/framework7io/framework7">Framework7</a></li>
<li><a target="_blank" href="https://flutter.dev/">Flutter</a></li>
<li><a target="_blank" href="https://www.nativescript.org/">NativeScript</a></li>
<li><a target="_blank" href="https://github.com/facebook/react-native">ReactNative</a></li>
<li><a target="_blank" href="https://github.com/ionic-team/ionic">Ionic</a></li>
<li><a target="_blank" href="https://cordova.apache.org/">Cordova</a> / <a target="_blank" href="https://phonegap.com/">PhoneGap</a></li>
<li><a target="_blank" href="https://github.com/meteor/meteor">Meteor</a></li>
<li><a target="_blank" href="https://dotnet.microsoft.com/apps/xamarin">Xamarin</a></li>
</ul>
<p>The list goes on for days.</p>
<p>I've used a few of these frameworks in the past. I've built a Meteor app which (surprisingly) worked. In the end I had to pick one though. What did I go with?</p>
<p><strong>NativeScript.</strong></p>
<p>For the most part, NativeScript's documentation and on-boarding experience is fantastic. Not only can you preview your app inside an emulator but you can load it directly to your phone too!</p>
<p><img src="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/images/Apple_iPhone_6s_Gold_-__status-b1ad9325-8e81-4ee0-b72a-687b62adec29.png" alt="images/Apple_iPhone_6s_Gold_-__status-b1ad9325-8e81-4ee0-b72a-687b62adec29.png" width="730" height="605" loading="lazy"></p>
<p>One of the cool things about NativeScript is that it supports TypeScript. TypeScript is a superset of JavaScript with some extra wiz-bang features. </p>
<p>Unlike other languages, JavaScript technically has no types. If you've done any Particle development you likely know what a type is. We're talking about <code>int</code>, <code>String</code>, <code>float</code> and more. i.e. they're directives to to make sure your JavaScript code stays consistent.</p>
<p>NativeScript is also compatible with most major JavaScript web frameworks. This includes <a target="_blank" href="https://vuejs.org/">Vue.Js</a> and <a target="_blank" href="https://angular.io/">Angular</a>.</p>
<p>I've only noticed one major drawback thus far: the mobile preview mode (<code>tns preview</code> command) does not pay well with native libraries. If you have some native platform specific libraries, you'll have to use the emulator or a device (if you have one).</p>
<p>If you're gung-ho and you <em>want</em> to build multiple apps in their respective languages, the more power to you. There is an advantage over the above frameworks: tried and true Particle SDKs.</p>
<h2 id="heading-available-libraries-amp-sdks">Available Libraries &amp; SDKs</h2>
<p>Particle has gone out of their way to make app development a little easier. This is thanks to the massive development work that has gone into their own SDKs. Yup, gone are the days you have to write manual HTTP request handlers.</p>
<p>Here's a link to both the iOS and Android SDKs:</p>
<ul>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/ios/">iOS</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/android/">Android</a></li>
</ul>
<p>Though we won't be covering them here, they reflect all the potential calls that you can make using the <a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">Cloud API.</a></p>
<p>Speaking of Cloud API, Particle has also developed a <a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">Node.js</a> library as well. As you can imagine, you can use this for your server side code or JavaScript based app frameworks. Sadly, it doesn't work with NativeScript. Frameworks that use a <a target="_blank" href="https://www.tutorialspoint.com/android/android_webview_layout.htm">WebView</a> should be more compatible.</p>
<p>In the case of this tutorial, we'll be mostly focusing on the Cloud API. This way you have a good understanding of the overall system. It may seem intimidating but if you do it right, you'll get the hang of it real fast.</p>
<h2 id="heading-making-api-calls">Making API Calls</h2>
<p>In NativeScript you can't use libraries like <code>[request](https://github.com/request/request)</code>. (Which happens to be the library Particle's very own <a target="_blank" href="https://github.com/dmiddlecamp">DMC</a> used in the <a target="_blank" href="https://github.com/particle-iot/particle-cli">CLI</a> — DMC if you're reading this, Hi!) You'll have to use the provided <a target="_blank" href="https://docs.nativescript.org/ns-framework-modules/http">HTTP</a> module. </p>
<p>If you scroll all the way to the <a target="_blank" href="https://docs.nativescript.org/ns-framework-modules/http#http-post">bottom of that page</a>, you'll see a fully fledged <code>POST</code> example. I'll reproduce it here but with some Particle specific changes:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Create form post data</span>
<span class="hljs-keyword">var</span> data = <span class="hljs-keyword">new</span> FormData();
data.append(<span class="hljs-string">"name"</span>, <span class="hljs-string">"update"</span>);
data.append(<span class="hljs-string">"data"</span>, <span class="hljs-string">"It's hammer time!"</span>);
data.append(<span class="hljs-string">"private"</span>, <span class="hljs-string">"true"</span>);
data.append(<span class="hljs-string">"access_token"</span>, _token);

<span class="hljs-comment">// Configure the httpModule</span>
<span class="hljs-keyword">return</span> httpModule
    .request({
        url: <span class="hljs-string">`https://api.particle.io/v1/devices/events`</span>,
        method: <span class="hljs-string">"POST"</span>,
        content: data
    })
    .then(
        <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
            <span class="hljs-keyword">const</span> result = response.content.toJSON();
            <span class="hljs-built_in">console</span>.log(result);
        },
        <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (e) <span class="hljs-built_in">console</span>.log(e);
        }
    );
</code></pre>
<p>The above is an example of what's equivalent to <code>Particle.publish</code> in DeviceOS. Let's break down the parts.</p>
<p>First of all, one of the main gotchas of Particle's Web API is the data format. I first expected that they use JSON but I was sorely wrong. After actually <em>reading</em> the documentation I realized that most POST requests were actually <code>application/x-www-form-urlencoded</code>. That means when you submit data, it's the equivalent to hitting the submit button on an HTML form.</p>
<p>Fortunately, there is an easy way to assemble form data in Node/JavaScript. We can use the <code>FormData()</code> object. Take a look at the above. There should be some familiar parameter names in the <code>data.append</code> calls.</p>
<p><code>"name"</code> refers to the name of the event you're publishing to.</p>
<p><code>"data"</code> refers to the string formatted data that you're publishing.</p>
<p><code>"private"</code> dictates whether or not you want to broadcast this data to the whole Particle world, or just your little corner of it.</p>
<p><code>"access_token"</code> is a token that you can generate in order to make these API calls. Without a token though, you're dead in the water.</p>
<h3 id="heading-getting-a-token">Getting a Token</h3>
<p>Where do we get this elusive <code>access_token</code>?</p>
<p>At first I had no idea.</p>
<p>I created an OAuth user and secret in the console. That lead to a dead end. Fiddled around with different API calls and settings. Nothing. Then it hit me like a ton of bricks. There's an <code>access_token</code> attached to the curl request on every device page!</p>
<p>Open up any device, click the little console button near <em>Events.</em> A popup with instructions an a URL will pop up. Copy the text after <code>access_token=</code>. That is your <code>access_token</code>! See below:</p>
<p><img src="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/images/Screen_Shot_2020-01-25_at_8.55.21_AM.png" alt="images/Screen_Shot_2020-01-25_at_8.55.21_AM.png" width="730" height="298" loading="lazy"></p>
<p>You can use this token to make calls to the Particle API. This can be to subscribe, publish, write to a function, read variables and more.</p>
<h3 id="heading-through-the-command-line">Through the command line</h3>
<p>That's nice and everything but how the heck can you <em>programmatically</em> generate one? One way is with the command line.</p>
<p><code>particle token create</code> is the name of the command you need to know about. When you run it, you'll be prompted to login. (Also enter your Authenticator code if you use one.) Then the command line will spit out a shiny new <code>access_token</code> you can use with the API!</p>
<h3 id="heading-through-the-api-itself">Through the API itself</h3>
<p>If you couldn't guess, <code>particle token create</code> is a <a target="_blank" href="https://github.com/particle-iot/particle-cli/blob/20d02afc7b72ade0e79d4f4ec724ec6cce9fff1b/src/lib/api-client.js#L192">frontend to a raw API call</a>. You can make these API calls directly too. Here's what it looks like in NativeScript.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Create form post data</span>
<span class="hljs-keyword">var</span> data = <span class="hljs-keyword">new</span> FormData();
data.append(<span class="hljs-string">"username"</span>, <span class="hljs-string">"jaredwolff"</span>);
data.append(<span class="hljs-string">"password"</span>, <span class="hljs-string">"this is not my password"</span>);
data.append(<span class="hljs-string">"grant_type"</span>, <span class="hljs-string">"password"</span>);
data.append(<span class="hljs-string">"client_name"</span>, <span class="hljs-string">"user"</span>);
data.append(<span class="hljs-string">"client_secret"</span>, <span class="hljs-string">"client_secret_here"</span>);

<span class="hljs-comment">// Configure the httpModule</span>
<span class="hljs-keyword">return</span> httpModule
    .request({
        url: <span class="hljs-string">`https://api.particle.io/v1/oauth/token`</span>,
        method: <span class="hljs-string">"POST"</span>,
        content: data
    })
    .then(
        <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
            <span class="hljs-keyword">const</span> result = response.content.toJSON();
            <span class="hljs-built_in">console</span>.log(result);
        },
        <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (e) <span class="hljs-built_in">console</span>.log(e);
        }
    );
</code></pre>
<p>This call <em>may</em> get more complicated. Mostly in the case if you have two factor authorization setup. It's well worth it when you figure it all out. After all, no one wants to manually create auth tokens if they don't have to!</p>
<p>Now you're ready to write and read from your devices. There's one thing though that may trip you up. Subscribing to events can be troublesome with a regular HTTP client. So much so that if you try to do it with NativeScript's HTTP client, it will lock up and never return. Luckily there is a way to handle these special HTTP calls.</p>
<h2 id="heading-server-sent-what">Server Sent What?</h2>
<p>Server Sent Events (SSE for short) is an HTTP/S subscription functionality. It allows you to connect to a SSE end point and continuously listen for updates. It's a similar web technology to what companies use for push notifications. It does require some extra functionality under the hood though...</p>
<h3 id="heading-sse-library">SSE Library</h3>
<p>After much head scratching and searching I stumbled upon <code>nativescript-sse</code>. It looked simple enough that I could start using immediately. More problems arose when I tried to use it though.</p>
<p>First, it turns out you can't use the library in <code>tns preview</code> mode. The alternative is to use <code>tns run ios --emulator</code> or use <code>tns run ios</code> with your iPhone connected to your computer. The non-emulator command will automatically deliver your prototype app.</p>
<p><strong>Side note:</strong> I had already set up my phone in Xcode. You may have to do this yourself before <code>tns run ios</code> is able to find and deploy to your phone.</p>
<p>Secondly, once I got the library working, I noticed I would get some very nasty errors. The errors seemed to happen whenever a new message from Particle came along. </p>
<p>Turns out the underlying Swift library for iOS <a target="_blank" href="https://github.com/inaka/EventSource/issues/89">had fixed this last year.</a> So I took it upon myself to figure out how to upgrade the NativeScript plugin. I'll save you the time to say that it can be a pain and there is a learning curve!</p>
<p>Fortunately after some hacking I got something working. More instructions on how to compile the plugin are in the <a target="_blank" href="https://github.com/jaredwolff/nativescript-sse">README</a>. Alternatively, you can download a pre-built one on the <a target="_blank" href="https://github.com/jaredwolff/nativescript-sse/releases/tag/v4.0.3">Release page of the repository.</a></p>
<p>Download the <code>.tgz</code> file to wherever you like. Then, you can add it using <code>tns plugin add</code>. The full command looks like this:</p>
<pre><code>tns plugin add path/to/plugin/file.tgz
</code></pre><p>You can check to make sure the library is installed by running <code>tns plugin list</code></p>
<pre><code>**jaredwolff$ tns plugin list
<span class="hljs-attr">Dependencies</span>:
┌─────────────────────┬──────────────────────────────────────────────────────────────────────────────────┐
│ Plugin              │ Version                                                                          │
│ @nativescript/theme │ ~<span class="hljs-number">2.2</span><span class="hljs-number">.1</span>                                                                           │
│ nativescript-sse    │ file:../../Downloads/nativescript-sse/publish/package/nativescript-sse<span class="hljs-number">-4.0</span><span class="hljs-number">.3</span>.tgz │
│ tns-core-modules    │ ~<span class="hljs-number">6.3</span><span class="hljs-number">.0</span>                                                                           │
└─────────────────────┴──────────────────────────────────────────────────────────────────────────────────┘
Dev Dependencies:
┌──────────────────────────┬─────────┐
│ Plugin                   │ Version │
│ nativescript-dev-webpack │ ~<span class="hljs-number">1.4</span><span class="hljs-number">.0</span>  │
│ typescript               │ ~<span class="hljs-number">3.5</span><span class="hljs-number">.3</span>  │
└──────────────────────────┴─────────┘
<span class="hljs-attr">NOTE</span>:
If you want to check the dependencies <span class="hljs-keyword">of</span> installed plugin use npm view &lt;pluginName&gt; grep dependencies
If you want to check the dev dependencies <span class="hljs-keyword">of</span> installed plugin use npm view &lt;pluginName&gt; grep devDependencies**
</code></pre><p>Once installed, invoking the library takes a few steps. Here's an example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { SSE } <span class="hljs-keyword">from</span> <span class="hljs-string">"nativescript-sse"</span>;

sse = <span class="hljs-keyword">new</span> SSE(
            <span class="hljs-string">"https://api.particle.io/v1/events/blob?access_token=&lt;your access token&gt;"</span>,
            {}

<span class="hljs-comment">// Add event listener</span>
sse.addEventListener(<span class="hljs-string">"blob"</span>);

<span class="hljs-comment">// Add callback</span>
sse.events.on(<span class="hljs-string">"onMessage"</span>, <span class="hljs-function"><span class="hljs-params">data</span>=&gt;</span>{
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> do stuff with your event data here!</span>
    <span class="hljs-built_in">console</span>.log(data);
});

<span class="hljs-comment">// Connect if not already</span>
sse.connect();
</code></pre>
<p>First you need to import and create an instance of the library. When you create the instance, you will have to enter the URL that you want to use. </p>
<p>In this case we'll be doing the equivalent of <code>Particle.subscribe()</code>. It should look something similar to the above: <code>https://api.particle.io/v1/events/&lt;your event name&gt;?access_token=&lt;your access token&gt;</code>. </p>
<p>Replace <code>&lt;your event name&gt;</code> and <code>&lt;your access token&gt;</code> with the name of your event and your freshly created token!</p>
<p>Then you set up the library to listen for the event you care about. In this case <code>blob</code> is the event I most care about.</p>
<p>Then make sure you configure a callback! That way you can get access to the data when <code>blob</code> does come along. I've made a <code>TODO</code> note where you can access said data.</p>
<p>Finally, you can connect using the <code>.connect()</code> method. If you don't connect, SSE will not open a session and you'll get no data from Particle.</p>
<p>Placement of the code is up to you but from the examples it looks like within the <code>constructor()</code> of your model is a good place.(<a target="_blank" href="https://github.com/jaredwolff/nativescript-sse/blob/master/demo/app/main-view-model.ts">https://github.com/jaredwolff/nativescript-sse/blob/master/demo/app/main-view-model.ts</a>)</p>
<h3 id="heading-other-examples">Other Examples</h3>
<p>If you're curious how to use SSE in other places I have another great example: Particle's CLI.</p>
<p>Particle uses the <code>[request](https://github.com/request/request)</code> library to handle SSE events in the app. Whenever you call <code>particle subscribe blob</code> it invokes a <code>getStreamEvent</code> further inside the code.  You can <a target="_blank" href="https://github.com/particle-iot/particle-cli/blob/master/src/lib/api-client.js#L862">check it out here.</a> The <code>request</code> library has more information on streaming <a target="_blank" href="https://github.com/request/request#streaming">here</a>.</p>
<h2 id="heading-more-resources">More resources</h2>
<p>This is but the tip of the iceberg when it comes to connecting with Particle's API. Particle has some great documentation (as always) you can check out. Here are some important links:</p>
<ul>
<li><a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">API documentation</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/javascript/">Javascript SDK</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/ios/">iOS SDK</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/android/">Android SDK</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this post we've talked about app frameworks, NativeScript, NativeScript plugins and Server Sent Events. Plus all the Particle related things so you can connect your NativeScript app to Particle's API. </p>
<p>I hope you've found this quick tutorial useful. If you have any questions feel free to leave a comment or <a target="_blank" href="https://www.jaredwolff.com/contact/">send me a message</a>. Also be sure to check out my <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-guide-to-particle-mesh/">newly released guide</a>. It has content just like this all about Particle's ecosystem.</p>
<p>Until next time!</p>
<p><strong>This post was originally from</strong> <a target="_blank" href="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/"><strong>https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/</strong></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Progressive Web Apps vs Accelerated Mobile Pages: What's the Difference and Which is Best for You? ]]>
                </title>
                <description>
                    <![CDATA[ Do you understand what PWAs and AMPs are, and which might be better for you? Let's have a look and find out. So many people own smartphones these days. This opens up endless opportunities for a business - opportunities which, however, are immediately... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/pwa-vs-amp-what-is-the-difference-and-how-do-you-choose/</link>
                <guid isPermaLink="false">66be14ce2728aa32fea75a32</guid>
                
                    <category>
                        <![CDATA[ AMP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PWA ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oleh Romanyuk ]]>
                </dc:creator>
                <pubDate>Tue, 07 Jan 2020 14:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/01/PWA-vs-AMP.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Do you understand what PWAs and AMPs are, and which might be better for you? Let's have a look and find out.</p>
<p>So many people own smartphones these days. This opens up endless opportunities for a business - opportunities which, however, are immediately challenged by the immense number of competitors in the mobile software market. </p>
<p>Mobile apps are surely more convenient than web or desktop platforms. Yet, they are not the most comfortable option that the industry offers.</p>
<p>To hit the highest level of user satisfaction and to outrun competitors, inventive people opt in favor of progressive web apps (PWAs) or accelerated mobile pages (AMPs).</p>
<p>What are these things, and how should you choose the best option? Let’s consider each one-by-one by going through these simple questions:</p>
<ol>
<li>What is a PWA?</li>
<li>What is an AMP?</li>
<li>How are they similar?</li>
<li>How are they different?</li>
<li>Why PWAs are better than web pages</li>
<li>Why PWAs are better than native mobile</li>
<li>Why AMPs are better than web pages</li>
<li>Why AMPs are NOT better than native mobile</li>
</ol>
<h2 id="heading-1-what-is-a-pwa">1. What Is a PWA?</h2>
<p>A progressive web application, or PWA, unites the advantages of both web and mobile apps into a single software product. As <a target="_blank" href="https://developers.google.com/web/progressive-web-apps">Google</a> declares, PWAs are “user experiences that have the reach of the web and are reliable, fast, and engaging”. It is a technology that lets you use a website as if it was a native app.</p>
<p><a target="_blank" href="https://twitter.com/?lang=en">Twitter</a> is one of the major companies using PWAs. To install the app, you open the web version on your phone and add it to your home screen. When you open Twitter from the home screen icon, you will be opening it as a progressive web app.</p>
<p><img src="https://images.ctfassets.net/6xhdtf1foerq/1TGtQag89baQtjFwQFRG1t/29cacc2916819498d669921833c88ceb/8-min.png?fm=png&amp;q=85&amp;w=1000" alt="PWA" width="1000" height="563" loading="lazy"></p>
<h3 id="heading-fundamentals">Fundamentals</h3>
<p>PWAs are a highly responsive and easily shareable solution, which can work offline. They store HTML and CSS files in the browser cache and archive them with service workers. This makes it possible to use the web page offline. Service workers are one of the three essential components of a PWA, along with the manifest file and a secure protocol HTTPS.</p>
<p><strong>Service workers</strong> are JavaScript code components which play the role of a proxy between the network and the browser. </p>
<p>When you open a web page for the first time, service workers store the necessary data in the browser cache. When you open it for the second time, service workers retrieve this data from the cache even before the app checked network availability. </p>
<p>Not only do they provide the ability to work offline but also they greatly boost the response time. Service workers also manage push notifications.</p>
<p><strong>The manifest file</strong> is a JSON file containing all the information about your app. For instance, it contains data about the home screen icon of your PWA, its short name, color palette, or theme. </p>
<p>If you are using the Chrome browser on an Android phone, the manifest file will trigger the automatic installation of the PWA onto your phone.</p>
<p><strong>The secure HTTPS protocol</strong> is an absolute must if you develop a progressive web app. While service workers make the very concept of a PWA possible, they are vulnerable to network errors or breaches. Service workers can intercept network requests and modify responses. To ensure data security and network security, the secure protocol needs to be used.</p>
<h3 id="heading-success-stories">Success stories</h3>
<p>Twitter is not the only company that has benefited from PWAs. Check out these <a target="_blank" href="https://developers.google.com/web/showcase/">case studies</a> published by Google to see how this technology helped popular businesses succeed. Among these companies are <a target="_blank" href="https://www.pinterest.com/">Pinterest</a>, <a target="_blank" href="https://www.alibaba.com/">Alibaba</a>, <a target="_blank" href="https://weather.com/">The Weather Channel</a>, <a target="_blank" href="https://www.lancome.com/">Lancome</a>, and <a target="_blank" href="https://www.homedepot.com/">The Home Depot.</a></p>
<h2 id="heading-2-what-is-an-amp">2. What Is an AMP?</h2>
<p>AMP stands for accelerated mobile page. It's a mobile-friendly web page, which is designed to be loaded instantly. It is a fast and smoothly loading solution which is developed with the user experience in mind. Introduced as an open-source project, the AMP technology was integrated by Google in February 2016.</p>
<p>In 2016, <a target="_blank" href="https://www.theguardian.com/membership/2016/feb/24/todays-release-of-accelerated-mobile-pages-amp">The Guardian announced</a> that their platform was now available as an AMP. To help readers see how it worked, they displayed the same article both as <a target="_blank" href="https://www.theguardian.com/us-news/commentisfree/2016/feb/16/thomas-piketty-bernie-sanders-us-election-2016">a web version</a> and <a target="_blank" href="https://amp.theguardian.com/us-news/commentisfree/2016/feb/16/thomas-piketty-bernie-sanders-us-election-2016">an AMP version</a>. </p>
<p>There were some differences, but they were insignificant. But what you'd notice right away was how much faster the AMP article loaded compared to the regular web article.</p>
<p><img src="https://images.ctfassets.net/6xhdtf1foerq/1ARjDXZC1yH4p15rxRosIW/e23cf5144729c5985e5a8ac156fb66a6/2.7_billion_people_use_smartphones__1_-min.png?fm=png&amp;q=85&amp;w=1000" alt="*By comparing this illustration with the one I included earlier, you could notice an interesting point. A PWA needs to be installed. In turn, you do not need to install AMP. It is accessed via a different like.
" width="1000" height="563" loading="lazy">
<em>*By comparing this illustration with the one I included earlier, you could notice an interesting point. A PWA needs to be installed. In turn, you do not need to install AMP. It is accessed via a different like.</em></p>
<h3 id="heading-fundamentals-1">Fundamentals</h3>
<p>The idea of AMPs is to reduce the amount of unnecessary content and functionality so that the app displays essential content immediately. The data can be reduced up to ten times. The three essential components of AMPs are AMP HTML, AMP Components, and the AMP Cache.</p>
<p><strong>AMP HTML</strong> is a simplified version of regular HTML. AMP HTML does not allow some tags and elements of HTML (for example, forms). To understand better what AMP HTML should look like, check out the <a target="_blank" href="https://amp.dev/documentation/guides-and-tutorials/start/create/basic_markup/?referrer=ampproject.org">required mark-up</a>.</p>
<p><strong>AMP Components</strong> are the scripts that enable you to do without JavaScript. The idea of AMP is to get rid of all JavaScript scripts as make pages load more slowly. </p>
<p>But this does not mean that your page should do without animations, modified layouts, analytics data, autocomplete suggestions, or ads. There is an extensive <a target="_blank" href="https://amp.dev/documentation/components/?referrer=ampproject.org">library of components</a> that enable you to implement these and a lot of other features.</p>
<p><strong>The AMP Cache</strong> is a proxy-based content delivery network which fetches and caches page content. AMP Cache enables you as an app owner to easily introduce page updates. It optimizes and, if needed, modifies the AMP.</p>
<h3 id="heading-success-stories-1">Success stories</h3>
<p>The same as with PWAs, companies are often very proud of the business advantages that AMPs offer. Here is a collection of <a target="_blank" href="https://amp.dev/success-stories/">success stories</a> and case studies of companies that used AMPs and benefited from them. <a target="_blank" href="https://www.musement.com/us/">Musement</a>, <a target="_blank" href="http://www.rcsmediagroup.it/">RCS MediaGroup</a>, <a target="_blank" href="https://www.cnbc.com/">CNBC</a>, <a target="_blank" href="https://www.washingtonpost.com/">The Washington Post</a> are all companies that have implemented or plan to implement AMPs.</p>
<h2 id="heading-3-how-are-pwas-and-amps-similar">3. How Are PWAs and AMPs similar?</h2>
<p>Both PWAs and AMPs are methods of displaying web pages on mobile devices. Both of them are created to enhance the user experience. </p>
<p>AMPs and PWAs both help reduce page load time. While AMPs may be slightly more effective in terms of loading speed than PWAs, the difference between AMP and PWA loading times is barely noticeable. </p>
<p>Both technologies are actively supported by Google. There is <a target="_blank" href="https://developers.google.com/web/progressive-web-apps">a PWA page on Google Developers</a> and <a target="_blank" href="https://developers.google.com/amp">an AMP page on Google Developers</a> as well.</p>
<p>There are not a lot of other similarities, but this primary similarity is essential. </p>
<p>Now let’s see what the differences are. </p>
<h2 id="heading-4-how-are-pwas-and-amps-different">4. How Are PWAs and AMPs Different?</h2>
<h3 id="heading-appearance">Appearance</h3>
<p>By using a PWA you do not feel like you are using a web page. PWAs look and feel like a mobile app.</p>
<p>By using AMPs, you are well aware that you are using a web page because it looks the same.</p>
<h3 id="heading-development">Development</h3>
<p>In the case of PWAs, the application code is written either from scratch or with some parts of the existing code.</p>
<p>In the case of AMPs, the existing code of a web page is stripped of unnecessary CSS and JS so that the web page loads faster.</p>
<h3 id="heading-user-experience">User experience</h3>
<p>PWAs offer a much better user experience. They have push-notifications, a home screen icon, and no browser tabs. Also, they are much easier to download and lighter in size than a regular mobile app. PWAs load faster than a regular web version because they are embedded with App Shell. And PWAs can be used when the network connection is down.</p>
<p>AMPs offer a slightly improved user experience since the page loads faster than a regular page. Still, this is the only UX advantage that they offer. Unlike PWAs, AMPs cannot work offline.</p>
<h3 id="heading-performance">Performance</h3>
<p>From an SEO standpoint, AMP wins the competition. Google favors these pages and lists them in the carousel of top stories, which can increase your click-through rate.</p>
<p>PWAs, in turn, do not have a direct advantage for SEO. However, better user experience translates into higher retention rates, which helps you win with SEO.</p>
<h3 id="heading-support">Support</h3>
<p>PWAs are not supported equally on all devices, so you may find slight inconveniences when they're displayed on iOS. Also, they do not support all the hardware functionalities, such as Bluetooth, NFC, GPS, or accelerometers.</p>
<p>AMPs are supported by all major browsers on all devices.</p>
<h3 id="heading-apps-theyre-best-suited-for">Apps they're best suited for</h3>
<p>PWAs work perfectly for apps that require user interactions. E-commerce websites, social media, or online learning platforms where the app needs to be responsive and constantly updated can make use of this technology. This is why Twitter uses a PWA, for example.</p>
<p>AMPs are more suitable for platforms with a wall of content, such as online magazines or newspapers. AMPs load content instantly, but the interaction opportunities are limited. This is why The Guardian decided to employ AMPs.</p>
<h2 id="heading-5-why-pwas-are-better-than-web-pages">5. Why PWAs Are Better Than Web Pages</h2>
<p>If you access a web page on mobile, you will have to deal with browser tabs, slow loading times, and annoying pop-ups. If your device has a relatively small screen or a slow network connection, surfing the web on it becomes unbearable.</p>
<p>This problem is solved by progressive web apps. In a few clicks, you install the app on your phone and get down to using it. No need to type a link, no browser tabs, and no pop-up screens. The app works fast, and it does work if the network connection is down.</p>
<p>Alright, the benefits of this solution are evident, but it seems like native mobile apps could work perfectly instead. No, they would not. Let’s see why PWAs are better than native mobile apps.</p>
<h2 id="heading-6-why-pwas-are-better-than-native-mobile-apps">6. Why PWAs Are Better Than Native Mobile Apps</h2>
<p>To use a native mobile application, you have to find it in the App Store or Google Play catalogs. Then, you have to wait for some time to download it. You might not have enough free space on your device, so you'll need to find some room.</p>
<p>In turn, PWAs are installed and ready to use in seconds. The file size is small (although it's bound to increase while you are using the app and it is caching). Still, the size of the cached data depends on the amount of free storage you have on your device.</p>
<p>As you can see, PWAs seem better than a web or native mobile app. But you should understand that this solution is not universal. Check out my recent article on <a target="_blank" href="https://keenethics.com/blog/progressive-web-apps-vs-native-which-to-choose-and-when">PWA vs Native</a> to learn when a native app is a better choice than a PWA.</p>
<h2 id="heading-7-why-amps-are-better-than-web-pages">7. Why AMPs Are Better Than Web Pages</h2>
<p>As mentioned above, web apps are slow and inconvenient, especially when accessed on mobile devices with small screen size or underpowered hardware.</p>
<p>By getting rid of all the web components that are unnecessary for a good user experience, accelerated mobile pages solve this problem. AMPs perform 4 times faster and use 10 times less data than regular web pages.</p>
<h2 id="heading-8-why-amps-are-not-better-than-native-mobile">8. Why AMPs Are NOT Better Than Native Mobile</h2>
<p>Unfortunately, AMPs cannot be a complete substitute for native mobile apps. They cannot be installed on the home screen, they still include browser tabs, and their functionality is limited to some basic stuff.</p>
<p>But for an online newspaper or for an informational website, such as <a target="_blank" href="https://www.webmd.com/">WebMD</a>, it is better to use AMPs rather than a native mobile app. These do not require any additional functionality for displaying page content.</p>
<h2 id="heading-to-wrap-up">To Wrap Up</h2>
<p>Both AMPs and PWAs are powerful technologies. To sum up the results of our initial question - PWAs vs AMPs: </p>
<ul>
<li>AMPs will be easier, faster, and cheaper for you to develop </li>
<li>PWA will offer more benefits.</li>
</ul>
<p>Just remember - neither of them is a universal solution, and neither is a panacea. Even using AMPs and PWAs together may not meet all your demands. Sometimes you may need to choose more conventional types of software. </p>
<p>If you are still not sure what to choose, our specialists share <a target="_blank" href="https://www.freecodecamp.org/news/four-questions-to-understand-if-you-need-pwa/">four questions to understand if you need PWA</a>. In short: <em>We believe that progressive web apps are the future. Accelerated mobile pages are just too simple and limited in functionality to compete.</em></p>
<h2 id="heading-do-you-have-an-idea-for-a-project">Do you have an idea for a project?</h2>
<p>My company KeenEthics is experienced in both AMP and <a target="_blank" href="https://keenethics.com/tech-apps-progressive-web-apps">progressive web app development</a>. If you are ready to change the game and start your project, feel free to <a target="_blank" href="https://keenethics.com/contacts">get in touch</a><em>.</em></p>
<h2 id="heading-ps">P.S.</h2>
<p>The original article posted on KeenEthics blog can be found here: <a target="_blank" href="https://keenethics.com/blog/pwa-vs-amp">PWA vs AMP:  What Is the Difference and How Do You Choose?</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to programmatically build a Spotify clone for iOS using AutoLayout: adding photos and updating the UI ]]>
                </title>
                <description>
                    <![CDATA[ By Said Hayani This is the second part of an article on building a Spotify UI clone with autoLayout programmatically. If you missed the first part, no worries - just please go and check it now.  In this article, we are going to add some mocked pictur... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-spotify-clone-for-ios-with-autolayout-programmatically-part-2/</link>
                <guid isPermaLink="false">66d460d2868774922c885008</guid>
                
                    <category>
                        <![CDATA[ 100DaysOfCode ]]>
                    </category>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ autolayout ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS13 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iphone ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ User Interface ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 10 Dec 2019 03:44:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/12/featured_image-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Said Hayani</p>
<p>This is the second part of an article on building a Spotify UI clone with autoLayout programmatically. If you missed the first part, no worries - just please go and <a target="_blank" href="https://www.freecodecamp.org/news/autolayout-programmatically-spotify-clone-in-swift/">check it now</a>. </p>
<p>In this article, we are going to add some mocked pictures and try to make the UI look the same as Spotify's.</p>
<p>This is what we are going to do today ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-09-at-9.55.19-PM-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is were we left off in the first part:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/complet-layout-demo1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The next step is to create customized cells. So let's start by creating one with the name  <code>SubCustomCell</code>.</p>
<p>First, create a new Swift file inside the project folder and name it <code>SubCustomCell.swift</code>. This file will contain our custom cell that will represent the Playlist. After creating the file, try to add in the code below and initialize the cell, maybe with <code>backgroundColor</code>,  to see the UI changes when we register the cell with the <code>collectionView</code>. </p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> UIKit

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SubCustomCell</span>: <span class="hljs-title">UICollectionViewCell</span> </span>{
        <span class="hljs-keyword">override</span> <span class="hljs-keyword">init</span>(frame: <span class="hljs-type">CGRect</span>) {
        <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>(frame: frame)
        backgroundColor = .red
    }

    <span class="hljs-keyword">required</span> <span class="hljs-keyword">init</span>?(coder aDecoder: <span class="hljs-type">NSCoder</span>) {
        <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"init(coder:) has not been implemented"</span>)
    }
}
</code></pre>
<p>Then we register the <code>SubCustomCell</code>  inside <code>CustomCell.swift</code> within the <code>init</code> block. Replace <code>UICollectionViewCell.self</code> with  <code>SubCustomCell</code> like below.</p>
<pre><code class="lang-swift"> collectionView.register(<span class="hljs-type">SubCustomCell</span>.<span class="hljs-keyword">self</span>, forCellWithReuseIdentifier: cellId)
</code></pre>
<p>Also we need to make a modification on the <code>cellForItemAt</code> method and make it conform to  <code>SubCustomCell</code> like the following.</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">SubCustomCell</span>
        <span class="hljs-comment">// cell.backgroundColor = .yellow</span>

        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>You should see the <code>backgroundColor</code> changed to <code>red</code> .</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-03-at-1.10.25-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Swift CustomCell</em></p>
<p>Up until this point everything should be straightforward and clear.</p>
<p>Now we're going to fill the cells with some mocked pictures and create an <code>ImageView</code> inside each cell. I already downloaded some random pictures from <a target="_blank" href="https://www.pexels.com/">pexels.com,</a> but feel free to use any pictures you like (including these). You can find them in the <a target="_blank" href="https://github.com/hayanisaid/autoLayout-programmatically-in-swift">project files on Github</a>.</p>
<p>Let's create the <code>UIImageView</code> inside <code>SubCustomCell.swift</code> and make some constraints.</p>
<pre><code class="lang-swift">    <span class="hljs-keyword">let</span> <span class="hljs-type">ImageView</span> : <span class="hljs-type">UIImageView</span> = {
       <span class="hljs-keyword">let</span> iv = <span class="hljs-type">UIImageView</span>()
        iv.backgroundColor = .yellow
        <span class="hljs-keyword">return</span> iv

    }()
</code></pre>
<p>And add it to the <code>view</code> within the <code>init</code> block using <code>addSubView</code>.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">override</span> <span class="hljs-keyword">init</span>(frame: <span class="hljs-type">CGRect</span>) {
        <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>(frame: frame)
        addSubview(<span class="hljs-type">ImageView</span>)

    }
</code></pre>
<p>Now let's make the <code>ImageView</code> take up all the space within the cell with the constraints below.</p>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">ImageView</span>.topAnchor.constraint(equalTo: topAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.leftAnchor.constraint(equalTo: leftAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.rightAnchor.constraint(equalTo: rightAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = <span class="hljs-literal">true</span>
</code></pre>
<ul>
<li><code>LeftAnchor</code> represents the left anchor of the cell</li>
<li><code>rightAnchor</code> represents the right anchor of the cell</li>
<li><code>bottomAnchor</code> represents the bottom anchor of the cell </li>
<li><code>topAnchor</code> represents the top anchor of the cell</li>
</ul>
<p>And by making <code>ImageView</code> 's top anchor equal to the cell's top anchor (and doing the same for <code>ImageView</code> 's left, right, and bottom anchor) it makes the <code>ImageView</code> take up all the space of the <code>SubCustomCell</code> (cell).</p>
<p>Note: first you need to use <code>translatesAutoresizingMaskIntoConstraints</code> to be able to apply the constraints to the elements. Also don't forget to call <code>isActive</code> property and assign it to <code>true</code> – without doing that the constraints won't work and nothing will change.</p>
<p>The <code>ImageView</code> should have an image, so let's add one.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">let</span> <span class="hljs-type">ImageView</span> : <span class="hljs-type">UIImageView</span> = {
       <span class="hljs-keyword">let</span> iv = <span class="hljs-type">UIImageView</span>()
        iv.backgroundColor = .yellow
        <span class="hljs-comment">// we have &gt;image1&lt; file inside the project </span>
        iv.image = <span class="hljs-type">UIImage</span>(named: <span class="hljs-string">"image1"</span>)
        iv.contentMode = .scaleAspectFill
        iv.clipsToBounds = <span class="hljs-literal">true</span>

        <span class="hljs-keyword">return</span> iv

    }()
</code></pre>
<p>And if you build and run the app, you should see the results and picture we added to the <code>SubCustomCell</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-03-at-1.37.51-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool ?. Now there is an element we should add to the <code>SubCustomCell</code> to finish up. We need a title that will represent the title of the playlist:  <code>UILabel</code>.</p>
<p>For the title it will be like this:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">let</span> <span class="hljs-type">TitleLabel</span> : <span class="hljs-type">UILabel</span> = {
        <span class="hljs-keyword">let</span> lb = <span class="hljs-type">UILabel</span>()
        lb.textColor = <span class="hljs-type">UIColor</span>.lightGray
        lb.font = <span class="hljs-type">UIFont</span>.systemFont(ofSize: <span class="hljs-number">16</span>)
        lb.font = <span class="hljs-type">UIFont</span>.boldSystemFont(ofSize: <span class="hljs-number">20</span>)
        lb.text = <span class="hljs-string">"Evening Music"</span>

        <span class="hljs-keyword">return</span> lb
    }()
</code></pre>
<p>I just put some random text there – you can put whatever you like. The next step is to add the element to the view and give it some constraints. The title will be placed at the bottom of the <code>ImageView</code>.</p>
<h3 id="heading-add-to-view">Add to view:</h3>
<pre><code class="lang-swift">addSubview(<span class="hljs-type">TitleLabel</span>)
</code></pre>
<h3 id="heading-applying-the-constraints-for-both-the-imageview-and-the-titlelabel">Applying the constraints for both the <code>ImageView</code> and the <code>TitleLabel</code></h3>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">ImageView</span>.topAnchor.constraint(equalTo: topAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.leftAnchor.constraint(equalTo: leftAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.rightAnchor.constraint(equalTo: rightAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.heightAnchor.constraint(equalToConstant: <span class="hljs-number">240</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: <span class="hljs-type">TitleLabel</span>.topAnchor).isActive = <span class="hljs-literal">true</span>



            <span class="hljs-type">TitleLabel</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">TitleLabel</span>.topAnchor.constraint(equalTo: <span class="hljs-type">ImageView</span>.bottomAnchor,constant: <span class="hljs-number">10</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">TitleLabel</span>.leftAnchor.constraint(equalTo: leftAnchor, constant: <span class="hljs-number">5</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">TitleLabel</span>.rightAnchor.constraint(equalTo: rightAnchor, constant: -<span class="hljs-number">5</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And here we go!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-06-at-1.45.10-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We made the picture take up most of the space in the cell, and the rest is taken up by the title. As you can see, you can scroll horizontally in each section and also vertically in the entire screen.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now we are put some mock data into the cells to make it feel like it's real. For that I created a <code>JSON</code> file that contains some random data for sections and playlists.</p>
<p>First let's create a two structs, <code>Section</code> and <code>Playlist</code> . We create a separate file for each struct. </p>
<p> <code>section.swift</code> </p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Foundation
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Section</span> </span>{
    <span class="hljs-keyword">var</span> title : <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> playlists : <span class="hljs-type">NSArray</span>
    <span class="hljs-keyword">init</span>(dictionary:[<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>]) {
        <span class="hljs-keyword">self</span>.title = dictionary[<span class="hljs-string">"title"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
        <span class="hljs-keyword">self</span>.playlists = dictionary[<span class="hljs-string">"playlists"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">NSArray</span> ?? []

}
}
</code></pre>
<p><code>playlist.swift</code></p>
<pre><code class="lang-swift"><span class="hljs-comment">//</span>
<span class="hljs-comment">//  playlist.swift</span>
<span class="hljs-comment">//  spotifyAutoLayout</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">//  Created by admin on 12/6/19.</span>
<span class="hljs-comment">//  Copyright © 2019 Said Hayani. All rights reserved.</span>
<span class="hljs-comment">//</span>

<span class="hljs-keyword">import</span> Foundation
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">PlayList</span> </span>{
    <span class="hljs-keyword">var</span> title: <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> image : <span class="hljs-type">String</span>
    <span class="hljs-keyword">init</span>(dictionary : [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>]) {
        <span class="hljs-keyword">self</span>.title = dictionary[<span class="hljs-string">"title"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
        <span class="hljs-keyword">self</span>.image = dictionary[<span class="hljs-string">"image"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
    }

}
</code></pre>
<p>And then inside <code>ViewController.swift</code> we create a function that fetches the JSON for us and stores the results in an array.</p>
<pre><code class="lang-swift">
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"attempt to fetch Json"</span>)
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> path = <span class="hljs-type">Bundle</span>.main.path(forResource: <span class="hljs-string">"test"</span>, ofType: <span class="hljs-string">"json"</span>) {
            <span class="hljs-keyword">do</span> {
                  <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">try</span> <span class="hljs-type">Data</span>(contentsOf: <span class="hljs-type">URL</span>(fileURLWithPath: path), options: .mappedIfSafe)
                  <span class="hljs-keyword">let</span> jsonResult = <span class="hljs-keyword">try</span> <span class="hljs-type">JSONSerialization</span>.jsonObject(with: data, options: .mutableLeaves)
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> jsonResult = jsonResult <span class="hljs-keyword">as</span>? [ <span class="hljs-type">Any</span>] {
                            <span class="hljs-comment">// do stuff</span>
                    jsonResult.forEach { (item) <span class="hljs-keyword">in</span>

                        <span class="hljs-keyword">let</span> section = <span class="hljs-type">Section</span>(dictionary: item <span class="hljs-keyword">as</span>! [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>])
                       <span class="hljs-comment">// print("FEtching",section.playlists)</span>
                        <span class="hljs-keyword">self</span>.sections.append(section)
                    }


                  <span class="hljs-keyword">self</span>.collectionView.reloadData()
                  }
              } <span class="hljs-keyword">catch</span> {
                   <span class="hljs-comment">// handle error</span>
              }
        }
    }
</code></pre>
<p>The <code>fetchJson</code> function is called within the <code>ViewDidLoad</code> method. We also have a variable called <code>sections</code> where we store the results:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> sections = [<span class="hljs-type">Section</span>]()
</code></pre>
<p>The next step is to pass the data from <code>ViewController</code> to <code>CustomCell</code>. For that we create a variable inside <code>CustomCell</code> which will receive the data for each section: </p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span>{
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
        }
    }
</code></pre>
<p>We use <code>cellForItemAt</code>  inside the <code>ViewController</code> method to pass the data directly to the <code>CustomCell</code> .</p>
<pre><code class="lang-swift"><span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">CustomCell</span>

        cell.section = sections[indexPath.item]

        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>Note: we always call <strong><code>self</code></strong><code>.collectionView.reloadData()</code> every-time <code>fetchJson</code> is called so the block below, inside <code>CustomCell</code>, will be called as well. Check the console, <code>shift</code> + command + C:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
        }
    }
</code></pre>
<p>The first thing we change is to set the the section title:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> section = <span class="hljs-keyword">self</span>.section <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-keyword">self</span>.titleLabel.text = section.title
        }
    }
</code></pre>
<p>And then you should see that each section has a specific title on the screen ?.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-06-at-3.23.32-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now it's time to pass the data down to <code>SubCustomCell</code>. We do the same thing as we did above. We need to pass the <code>playlists</code> array, so we create a variable named <code>playlists</code> inside <code>CustomCell</code>.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> playlists : [<span class="hljs-type">PlayList</span>]() <span class="hljs-comment">//empty</span>
</code></pre>
<p>First, we map through the <code>playlists</code>  from the <code>JSON</code>. Then we add each playlist with the <code>playlists</code> var.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> section = <span class="hljs-keyword">self</span>.section <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-keyword">self</span>.titleLabel.text = section.title
            <span class="hljs-comment">// append to playlists array</span>
             <span class="hljs-keyword">self</span>.section?.playlists.forEach({ (item) <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">let</span> playlist = <span class="hljs-type">PlayList</span>(dictionary: item <span class="hljs-keyword">as</span>! [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>])
                <span class="hljs-keyword">self</span>.playlists.append(playlist)

            })
            <span class="hljs-keyword">self</span>.collectionView.reloadData()
        }
    }
</code></pre>
<p>Attention! If you try to run the app it may crash. This is because we forgot to set the number of sections. Since we are now receiving the data from JSON, the number should be dynamic based on the number of sections we have. The number of sections should be equal to the number of sections inside the <code>JSON</code>, so we need to modify <code>numberOfItemsInSection</code> inside <code>ViewController</code> to the below :</p>
<pre><code class="lang-swift">   <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span> sections.<span class="hljs-built_in">count</span>
    }
</code></pre>
<p>We do the same thing with the same method inside <code>CustomCell.swift</code> – but here we consider the number of the <code>playlists</code> instead.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span>  <span class="hljs-keyword">self</span>.playlists.<span class="hljs-built_in">count</span>
    }
</code></pre>
<p>The last step we have to complete is to pass each single playlist <code>Object</code> to <code>SubCustomCell</code> within <code>cellForItemAt</code> in <code>CustomCell.swift</code>. </p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">SubCustomCell</span>
        <span class="hljs-comment">// here ?</span>
        cell.playlist = playlists[indexPath.item]
        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>And we are going to get that data inside <code>SubCustomCell</code> via the <code>playlist</code> variable and finally display the title and image of the playlist.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">var</span> playlist : <span class="hljs-type">PlayList?</span> {
           <span class="hljs-keyword">didSet</span>{
               <span class="hljs-built_in">print</span>(<span class="hljs-string">"Playlist ?"</span>,<span class="hljs-keyword">self</span>.playlist)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> playlist = <span class="hljs-keyword">self</span>.playlist <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-comment">// The Image ?</span>
            <span class="hljs-keyword">self</span>.<span class="hljs-type">ImageView</span>.image = <span class="hljs-type">UIImage</span>(named: playlist.image)
            <span class="hljs-comment">// the playlist title ?</span>
            <span class="hljs-keyword">self</span>.<span class="hljs-type">TitleLabel</span>.text = <span class="hljs-keyword">self</span>.playlist?.title

           }
       }
</code></pre>
<p>I think everything should work fine now, just as below ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo3.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p> One last update to the UI: we have to add some padding and margins to the <code>section</code>  and <code>playlist</code> titles and make the playlist a little bit smaller.</p>
<p>Let's first add some padding for the section titles. To do that, we need just to give the <code>constant</code> property some number value inside the section cell <code>CustomCell</code> and within <code>setupSubCells</code>: </p>
<pre><code class="lang-swift"> collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor,constant: <span class="hljs-number">15</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And if you see the entire <code>collectionView</code> come in at the bottom of the <code>titleLabel</code>, all we need to do is add more space by adding <code>15</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/paddingForTitles-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Next we come to the title of the <code>playlist</code>. This will be inside <code>SubCustomCell</code>, and we just need to add more space at the bottom of the ImageView.</p>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: <span class="hljs-type">TitleLabel</span>.topAnchor,constant: -<span class="hljs-number">15</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>We already have the constant there. In order for it to work, the value should be <code>-15</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo4.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Finally the playlist needs to be a little bit smaller. This is easy: we just make the <code>playlist</code> cell's height and width equal to the <code>section</code> cell's height divided by 2, just like below:</p>
<p><code>CustomCell.swift</code></p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">CGSize</span> {

        <span class="hljs-keyword">let</span> width = frame.height / <span class="hljs-number">2</span>
        <span class="hljs-keyword">let</span> height = frame.height / <span class="hljs-number">2</span>

        <span class="hljs-keyword">return</span> <span class="hljs-type">CGSize</span>(width: width, height: height)

    }
</code></pre>
<p>Make the ImageView's height equal to <code>150</code> as well.</p>
<pre><code class="lang-swift">  <span class="hljs-comment">//SubCutomCell.swift</span>
  <span class="hljs-type">ImageView</span>.heightAnchor.constraint(equalToConstant: <span class="hljs-number">150</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And here we go ?.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-09-at-9.55.19-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Perfect! I think that's enough for today – I don't want to make this article too long. So we will have another part where we will add the <code>TabBar</code> and the description, as well as some icons for the playlist.</p>
<p><strong>View the</strong> <a target="_blank" href="https://github.com/hayanisaid/autoLayout-programmatically-in-swift"><strong>Full source code on GitHub</strong></a><strong>?.</strong></p>
<p>Thanks for your time. I hope I haven't missed anything. If I did please @mention me on <a target="_blank" href="https://twitter.com/SaidHYN">Twitter</a>, or if you have any questions or an addition to this post the doors are always open to anyone. Thanks??.</p>
<p><strong><a target="_blank" href="https://webege.us16.list-manage.com/subscribe?u=311846a57d1e1a666287ad128&amp;id=2b386b2ebb">Subscribe</a></strong> <em>to my email list to be notified when the third part of this tutorial is published.</em> </p>
<blockquote>
<p>By the way, I’ve recently worked with a strong group of software engineers for one of my mobile applications. The organization was great, and the product was delivered very quickly, much faster than other firms and freelancers I’ve worked with, and I think I can honestly recommend them for other projects out there. Shoot me an email if you want to get in touch — <a target="_blank" href="mailto:said@devsdata.com">said@devsdata.com</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use freeCodeCamp on a mobile phone ]]>
                </title>
                <description>
                    <![CDATA[ By Jackson Bates For 5 years, freeCodeCamp has been helping millions to learn to code for...well...free! The low cost has opened up a world of opportunity to those that could not afford a bootcamp or the many expensive courses available. However, the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/freecodecamp-mobile/</link>
                <guid isPermaLink="false">66d45f3547a8245f78752a50</guid>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 18 Oct 2019 20:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/10/commlinechic-3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jackson Bates</p>
<p>For 5 years, freeCodeCamp has been helping millions to learn to code for...well...free!</p>
<p>The low cost has opened up a world of opportunity to those that could not afford a bootcamp or the many expensive courses available. However, there has been one barrier to entry for some - the necessity to use a laptop / desktop PC.</p>
<p>Coding on freeCodeCamp has been <em>possible</em> on a mobile device, but it's never been a comfortable experience - until today!</p>
<p>With the 5th birthday of freeCodeCamp comes a wonderful gift to the developer community: the new <em>Command Line Chic</em> interface, which includes a far superior mobile experience than has previously been available.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/commlinechic.gif" alt="Image" width="600" height="400" loading="lazy">
<em>The new responsive command line chic interface, with a clean mobile text editor</em></p>
<h2 id="heading-making-the-most-of-mobile-coding">Making the most of mobile coding</h2>
<p>Maybe you've tried using your mobile device for coding on freeCodeCamp before and noticed an annoying bug - it's impossible to delete things properly!</p>
<p>If you have encountered this, the cause of the problem is simple - your keyboard suggestions are treating the individual characters as longer strings. I haven't investigated this in detail, but my intuition is that it's deleting the html entity code.</p>
<p>The fix is simple - turn off auto suggestions, or better yet <strong>use a dedicated coding keyboard for your device</strong>. </p>
<p>This has the added benefit of making they keys you use often for programming (but not natural language) more easily available, such as brackets, braces and other special characters.</p>
<h2 id="heading-coding-keyboards-for-your-mobile-device">Coding keyboards for your mobile device</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/codeboard.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodeBoard for Andoid</em></p>
<p><a target="_blank" href="https://play.google.com/store/apps/details?id=com.gazlaws.codeboard">CodeBoard for Android</a> provides a packed keyboard of all the keys you are likely to need while completing the freeCodeCamp curriculum. The board is a little too crowded on a phone (although I still use it and have gotten used to it), but on a tablet it is a perfect companion.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/ioscodeboard.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>DevKey for iOs</em></p>
<p><a target="_blank" href="https://apps.apple.com/us/app/devkey-developer-keyboard-for-programming/id961304986">DevKey for iOs</a> presents a much less crowded interface, while still providing most of the keys you are likely to need. I can't personally endorse this, since I do not have an iPhone - but needless to say it presents a better experience for mobile coding than the standard keyboards.</p>
<h2 id="heading-coding-on-the-go">Coding on the go!</h2>
<p>Now that you've supercharged your mobile learning environment, you can take those freeCodeCamp lessons with you wherever you go, without the need for a clunky laptop hotspotting off your phone.</p>
<p>One thing that I'm really looking forward to is using the new interface and my mobile set-up to increase my participation on the <a target="_blank" href="https://freecodecamp.org/forum">freeCodeCamp forum</a>! I've always primarily engaged with the forum on my phone, but have struggled to help with coding challenges due to the previously poor mobile experience. Now, you can expect to get even more help from me and hopefully others!</p>
<p>Happy birthday, freeCodeCamp, and happy coding, y'all!</p>
<p> You can follow my more informal tech ramblings on Twitter <a target="_blank" href="https://twitter.com/jacksonbates">@JacksonBates</a>!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The story of one mother & two sons: value type vs reference type in Swift ]]>
                </title>
                <description>
                    <![CDATA[ By Boudhayan Biswas Swift is a mother?and it has two sons ?- Value Type ??‍♀️ Reference Type ?‍♂️ But what are their characteristics??‍♂️ Do they behave the same or opposite to each other? ?‍♂️ Swift is a multi-paradigm programming language develop... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-story-of-one-mother-two-sons-value-type-vs-reference-type-in-swift-6e125af2d5d0/</link>
                <guid isPermaLink="false">66d45de255db48792eed3f49</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 21 May 2019 16:47:32 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*Ri49w8TcHeXrnmO5dD4_aQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Boudhayan Biswas</p>
<p>Swift is a mother?and it has two sons ?-</p>
<ul>
<li>Value Type ??‍♀️</li>
<li>Reference Type ?‍♂️</li>
</ul>
<p>But what are their characteristics??‍♂️</p>
<p>Do they behave the same or opposite to each other? ?‍♂️</p>
<p>Swift is a multi-paradigm programming language developed by Apple for iOS, macOS, watchOS, tvOS, Linux, and z/OS.?</p>
<p>Just like other object-oriented programming languages, Swift has classes as building blocks which can define methods, properties, initializers, and can conform to protocols, support inheritance &amp; polymorphism.?</p>
<p>But, wait wait wait…???</p>
<p>Swift has structs also and it can define methods, properties, initializers and can conform to protocols with only one exception of inheritance.?</p>
<p>What? Now I am confused!!! ???</p>
<p>Now let’s spice up your confusion: structs are not only the value types in Swift. Tuples and enums are also value types. Classes are also not the only one used as a reference type. Functions and closures are also reference types. But as a token of relief, we at least know the primary focus &amp; specialization of usage of these types.?</p>
<p>So up to this point, we are left with only one big confusion with the usage of structs and classes.?</p>
<p>So, let’s go and clear the confusions going around.?‍♂️</p>
<h3 id="heading-storage-locations">Storage Locations</h3>
<p>There are three types of storage available:</p>
<ul>
<li>Register ?</li>
<li>Stack ☄️</li>
<li>Heap ?</li>
</ul>
<p>The objects that have a shorter lifespan are stored inside registers or the stack and those that have a longer lifespan are stored inside the heap.?</p>
<p>A value type stores its contents in memory allocated in the stack, so we can say value types are allocated in the stack in Swift. ?</p>
<p>But there is a common misconception about value types, have you heard it??‍♂️</p>
<p>The misconception is that most people think value types are always stored in the Stack.</p>
<p>❌❌ Wait a minute — this is not the case always. ❌❌</p>
<p>Value types can be stored inside the stack when they are either temporary or local variables. But what if a value type is contained inside a reference type?</p>
<p>In this situation, it can be stored inside the heap memory. ?</p>
<p>Wow…that’s cool!!!?</p>
<p>So the value types can be stored inside the register, stack or heap depending on their lifespan, whether they are short lived or long lived. If it is a local variable it can live inside the stack and if it is a part of class then it can live inside heap memory also.✅</p>
<p>On the other hand, reference type stores its contents in memory allocated in the heap memory and the variable holds only a reference to that memory location where actual data has been stored. ??</p>
<p>How does it work for reference type??</p>
<p>So for reference type, it is quite a common situation when there can be several variables holding the reference to the same memory location.⚔️</p>
<p>When a value type instance is assigned to a variable or passed to a function, the instance is copied and assigned to that variable. But with the reference type, only the reference gets copied and the new variable holds the same reference to the same memory location. ?</p>
<h3 id="heading-differences-in-terms-of-mutability">Differences in terms of Mutability</h3>
<p>There can be two states for a variable:</p>
<ul>
<li>?‍♀ ️Mutable ?‍♀</li>
<li>?️‍♂️ Immutable ?️‍♂️</li>
</ul>
<p>If a value type instance is assigned to an immutable variable, then the instance also becomes immutable. As a result, we can not make any changes to that instance.?‍♂️</p>
<p>If a value type instance is assigned to a mutable variable, then only it makes the instance mutable. ?‍♂️</p>
<p>But things are totally different for reference types. The variable and the instance it is assigned to are totally different. If we declare an immutable variable holding a reference to a class, this means that the reference it is holding will never change. We can not the change the reference and it will always point to the same reference. ?</p>
<h3 id="heading-structural-types">Structural Types</h3>
<p>Values of structural types are compared for equality in terms of their attributes or elements. We can say a value type is equal to another if and only if all of the corresponding attributes are equal. ???</p>
<p>Umm…too many strong words…what do you mean???</p>
<p>Let’s say, we have a <strong><em>Person</em></strong> value type which has attributes like <strong><em>firstName</em></strong> and <strong><em>lastName.</em></strong></p>
<pre><code>struct Person {
   <span class="hljs-keyword">var</span> firstName: <span class="hljs-built_in">String</span>
   <span class="hljs-keyword">var</span> lastName: <span class="hljs-built_in">String</span>
}

<span class="hljs-keyword">var</span> person1 = Person(firstName: <span class="hljs-string">"foo"</span>, <span class="hljs-attr">lastName</span>: <span class="hljs-string">"bar"</span>)

<span class="hljs-keyword">var</span> person2 = Person(firstName: <span class="hljs-string">"foo"</span>, <span class="hljs-attr">lastName</span>: <span class="hljs-string">"bar"</span>)
</code></pre><p>Here both <strong><em>person1</em></strong> &amp; <strong><em>person2</em></strong> instances are holding the same value for <strong><em>firstName</em> (“foo”)</strong> and <strong><em>lastName (“bar”)</em></strong><em>.</em> So as per our understanding, we can say that the two instances are equal to each other since their attributes (<strong><em>firstName</em></strong> &amp; <strong><em>lastName</em></strong>) are holding the same values.</p>
<p>But it’s not only limited to this: in the future, any two person instances holding the same values for <strong><em>firstName</em></strong> &amp; <strong><em>lastName</em></strong> will be equal to each other.</p>
<p>So as per our understanding till this point, we can say that:</p>
<blockquote>
<p><em><strong>Value Types do not have identity, so there can be no reference to them. Value types are faceless.?</strong></em></p>
</blockquote>
<p>What? How can you say that????</p>
<pre><code><span class="hljs-keyword">var</span> myAge: Int = <span class="hljs-number">21</span>
<span class="hljs-keyword">var</span> friendAge: Int = <span class="hljs-number">21</span>
</code></pre><p>Both <strong><em>myAge</em></strong> &amp; <strong><em>friendAge</em></strong> are integer type variable with value 21.</p>
<p><strong><em>Can we distinguish one from the other? ?</em></strong></p>
<p>No, because they are holding the same value.?</p>
<p>An integer variable with value 21 cannot be different from another integer variable which is also having the value 21. As simple as that.???</p>
<p>Not having an identity gives value types another advantage: if you think practically, then you can imagine if you do not have an identity then anyone with same characteristics can replace or substitute you. ???</p>
<p>The same we can think for us as humans also. If I don’t have an identity then anyone with same characteristics can replace me???. It’s good for us that we have an identity otherwise it would be a great risk to our existence.?</p>
<p>But for value types, they don’t have an identity and it is an advantage to them. ?</p>
<h3 id="heading-what-are-the-benefits-of-using-value-types">What are the benefits of using Value Types?</h3>
<h4 id="heading-no-race-conditions-and-deadlocks">? No Race Conditions and Deadlocks: ?</h4>
<p>For values types in a multi-threaded environment, it is impossible for one thread to mutate the state of the instance while it is being used by another thread. So we can say that there will be no race conditions or deadlocks.</p>
<h4 id="heading-no-retain-cycles">⚔️ <strong>No Retain Cycles: ⚔️</strong></h4>
<p>When there are two reference type instances that are holding strong references to each other and preventing each other from being deallocated from memory, it is called a retain cycle. Since value types don’t work as a reference, so we can say there will be no retain cycles for value types.</p>
<h4 id="heading-automatic-reference-counting">?‍?‍?‍? Automatic Reference Counting: ?‍?‍?‍?</h4>
<p>For reference type, Swift uses automatic reference counting to keep track of all the live or active objects and deallocates the instance only when there are no more strong references to it. If we think a little bit, then we can say that it is kind of a heavy operation because Swift runtime needs to keep track of the objects always. But since value types are allocated in the stack, it does not need ARC. So it is cheaper and faster??.</p>
<p>But wait...How does it manage memory for Array, Dictionary and String??</p>
<p>Since we can not know what will be the actual size of an array, a dictionary, and a string at compile time, there is no scope for them to be allocated at compile time. Though they are value types internally, they can not be allocated in stack. They need to be allocated in heap memory, and to manage this, Swift comes up with <strong><em>copy on write</em></strong>.?</p>
<p>But what is this??</p>
<p>When we say one instance is a copy of another instance, this really means they are the same, that they contain the same values. But in Swift, for these above types (Array, Dictionary, String, etc), an actual copy has been made on heap only when an instance is mutated. This is called a performance optimization technique for value types.???</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>There is no hard rule which defines when to use value type and when to use reference type. Value types have some unique advantages over reference types and vice versa. They both are unique in their own way. It really depends on your requirements and what you are trying to achieve. You should know the semantics of your code because you only know your code best, so it’s up to you to choose. You have the full freedom.</p>
<p>So rather than fighting over value type vs reference type, use them intelligently.</p>
<p><strong><em>??? Cheers!!! Thank you for reading!!</em></strong> <em>???</em></p>
<p><strong><em>✅✅✅You can find me on</em></strong> <a target="_blank" href="https://twitter.com/_boudhayan_"><strong><em>Twitter</em></strong></a><strong><em>.✅✅✅</em></strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to choose the best tech career path for you ]]>
                </title>
                <description>
                    <![CDATA[ By Colin Smith Dev Ops, Mobile Engineer, Data Scientist, Project Manager, and Front End — what’s best for you? _Get more info before you blindly choose your future career path. Photo by [Unsplash](https://unsplash.com/photos/ZFYg5jTvB4A?utm_source=u... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-choose-the-best-tech-career-path-for-you-61c4d5ff9a77/</link>
                <guid isPermaLink="false">66c3508d5ced6d98e4bd3343</guid>
                
                    <category>
                        <![CDATA[ careers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 04 Feb 2019 17:10:57 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*1sibiTjlpM5AY_bkS0Zdvg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Colin Smith</p>
<h4 id="heading-dev-ops-mobile-engineer-data-scientist-project-manager-and-front-end-whats-best-for-you">Dev Ops, Mobile Engineer, Data Scientist, Project Manager, and Front End — what’s best for you?</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/2CF0UBu9Vpz5Ga39bgLilZjt0uQhgyk3gGwi" alt="Image" width="800" height="545" loading="lazy">
_Get more info before you blindly choose your future career path. Photo by [Unsplash](https://unsplash.com/photos/ZFYg5jTvB4A?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Robert Anasch on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=").</em></p>
<p>I’ve worked in tech for four years, and I still come across roles that I don’t understand very well. There are so many ways to build a career in tech. I know that when I started looking for my first job, I was clueless about the differences between career paths. If you asked me what a site reliability engineer did, I wouldn’t have been able to tell you.</p>
<p>I get a lot of questions about career paths in tech. I thought I would write an article about it so I could point people to it. I’ll be using Business Insider’s article listing the <a target="_blank" href="https://www.businessinsider.com/best-tech-jobs-in-america-2018-2">20 best tech jobs in America in 2018 as a reference</a>. This is a good list of relevant tech paths with good upward mobility. They are highly in demand and will allow you to get a job at a good company with good pay. Hopefully, this will help you decide the path you will take. So let's start:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/BMXx4ncbet3Sf2DEBL608i8aF54kxLBvC77d" alt="Image" width="800" height="533" loading="lazy">
_Mobile devices have deeply integrated into our lives. For better or for worse. Photo by [Unsplash](https://unsplash.com/photos/5AYP1yeaE3I?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;rawpixel on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-mobile-developer">Mobile Developer</h3>
<p><strong>What do they do?</strong></p>
<p>Mobile developers are the people that build apps for companies. If you’ve ever used an Android or iOS device, then you’ve directly interacted with a mobile developer’s work. There are other development platforms for mobile such as Windows phone. But for the most part, when people say “Mobile Developer”, they’re most likely talking about an Android or iOS developer.</p>
<p><strong>Why should I choose this career path?</strong></p>
<p>You should become a mobile developer if you want to <strong>use your eye for design and attention to visual detail alongside your technical prowess</strong>. Mobile developers work heavily with designers to put out beautiful, easy to use and performant mobile apps.</p>
<p>You should also choose this path if you are interested in mobile devices and how they work. Mobile developers that focus on infrastructure have to consider limited device resources. They also must have in-depth knowledge of how a mobile device works to make the apps they work on performant.</p>
<p><strong>How do I get started?</strong></p>
<p>This depends on if you want to focus on iOS or Android. I’d personally recommend learning Android for two reasons. Java is probably a more useful language to learn over Swift or Objective-C and the fact that 75% of the world uses Android compared to 21% using iOS. <a target="_blank" href="http://gs.statcounter.com/os-market-share/mobile/worldwide">This is according to statcounter.com</a>. That being said, if you have a particular passion for one platform over the other, go with your passion.</p>
<p>For Android, <a target="_blank" href="https://android.jlelse.eu/learning-android-development-in-2018-part-1-83a514f6a205">read this article</a>. This goes over the nitty-gritty of how to get started. For iOS, <a target="_blank" href="https://www.raywenderlich.com/5993-your-first-ios-app/lessons/1">watch this video on raywenderlich.com</a>. Ray Wenderlich’s website is an excellent resource for iOS in general.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/11NWKdEgqi660Qd0I14wXZXpUqr-783XV9R2" alt="Image" width="800" height="600" loading="lazy">
_Insights derived from data tend to deliver better results than gut feelings from founders. Photo by [Unsplash](https://unsplash.com/photos/1K6IQsQbizI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Franki Chamaki on &lt;a href="https://unsplash.com/search/photos/data?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-data-scientist">Data Scientist</h3>
<p><strong>What do they do?</strong></p>
<p>Data scientists help businesses solve problems through the processing of data. So what does that mean? A software engineer will implement some logging somewhere on a website or mobile app. This gets processed and eventually gets to the data scientists. The data scientists will then gather all these data points and derive insights from them.</p>
<p>We can use an e-commerce website as an example. After looking at a few different data points, a data scientist notices that only 0.5% of people that add an item to the cart end up making a purchase. The data scientist then hypothesizes that this could be the reason for the decline in revenue last month. They check the rate three months ago and see that it was at 5%.</p>
<p>It looks like that is probably the reason for the drop in revenue. They surface this to the right stakeholders. These stakeholders find out that there was a crash occurring during purchasing that caused the problem. This may not have been found if a data scientist didn’t work at the company.</p>
<p>Data scientists can also work to spot new paths to growth and ways to improve current products based off of data. <strong>The sky is the limit on how a data scientist can be leveraged at a company.</strong></p>
<p><strong>Why should I choose this career path?</strong></p>
<p>Become a data scientist if you love looking at data and trying to see patterns. Data scientists provide value by looking over data and trying to discover insights that will help their company grow. You have to love trying to come up with reasons for why specific patterns are occurring. You also have to have a deep understanding of the products you are working with, so you can vet hypotheses around your data insights.</p>
<p><strong>How do I get started?</strong></p>
<p>I would start with <a target="_blank" href="https://www.coursera.org/learn/decision-making?siteID=SAyYsTvLiGQ-qF51g6iB4QYpdQ7g0Fsh3g&amp;utm_content=10&amp;utm_medium=partners&amp;utm_source=linkshare&amp;utm_campaign=SAyYsTvLiGQ">this course on Coursera</a> which first gives you a better understanding of how data drives business decisions. If that course deepens your interest, start with <a target="_blank" href="https://medium.freecodecamp.org/i-ranked-all-the-best-data-science-intro-courses-based-on-thousands-of-data-points-db5dc7e3eb8e">this article</a> that recommends some great ways to start learning.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/682u2vw7Krtlkh2jFFdCymZdyjQfSP8es26l" alt="Image" width="800" height="1200" loading="lazy">
_Being a project manager requires maintaining a perfect balance between delivery date and quality. Photo by [Unsplash](https://unsplash.com/photos/flEStjHTY14?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Leio McLaren (@leiomclaren) on &lt;a href="https://unsplash.com/search/photos/balance?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-project-manager">Project Manager</h3>
<p><strong>What do they do?</strong></p>
<p>Project managers do exactly what their title implies, they manage products. But what exactly does that mean? Well, as a project manager, you need to have a high level view of the product you are working on.</p>
<p>You need to make sure everyone is executing and working on the most relevant tasks so you can ship your product on time. You need to understand what every person on the team is doing, how they’re doing it and when they’ll be done. You line up all the pieces so that the final product has everything it needs in the timeline you provided to the higher-ups.</p>
<p>This also means you need to help unblock people when they’re stuck. You need to organize meetings with other teams if you are dependent on them for finishing your product. You need to run sync up meetings for your team to ensure everyone is on track and not having issues.</p>
<p>The hardest part about being a project manager is ensuring that everything gets done on time and with quality. You also need to make sure the people on your team aren’t overwhelmed. This is always a delicate balance.</p>
<p><strong>Why should I choose this career path?</strong></p>
<p>You are organized and love collaborating with others. You are able to balance the needs of many in order to deliver on a high quality product. You understand the trade off between time and quality and know when to push back for either.</p>
<p>Lets say the people waiting for your product demand that you finish it in 2 months when you know it will take 4 months to deliver a quality product. You must have the ability to provide convincing evidence for why you need the extra time. You also have to ensure that you don’t bow to pressure.</p>
<p><strong>Being a project manager requires maintaining a perfect balance between delivery date and quality.</strong></p>
<p>The opposite can be true also. Sometimes developers say that something will take 1 month when you’ve seen it done in 3 days before. You ask questions and find out that the developer wants to over-engineer this certain piece of work even though you know the product doesn’t need it. You have to figure out a way to get the developer to only build what is needed.</p>
<p>Like I said before, being able to work effectively with others while being organized and keeping a product on track is what it is all about. This is incredibly difficult. You need to have high level knowledge of a product but deep enough knowledge about every piece that you can keep people accountable for their work.</p>
<p><strong>How do I get started?</strong></p>
<p>A lot of project managers in tech use Agile and Scrum methodologies to organize their work. I would get started by looking into obtaining Scrum certifications. Take a look at the <a target="_blank" href="https://www.scrum.org/">Scrum website for more details.</a></p>
<p>Project manager’s tend to have a business administration degree or a project management degree. If you are already working on a computer science degree, you can consider getting a minor in one of these subject areas.</p>
<p>Another great way to get into project management is to manage a small project with your friends or an open source project. Practice makes perfect and real life application of project management skills will make you stand out as a candidate.</p>
<p>You can also start getting familiar with project management tools such as Trello, Jira, Quip, Excel and many more. Being familiar with the software a project manager uses will help you build your skills in project management.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/KjGOn6GcozEw3XKWvc5AYf-raga5A3PntdZa" alt="Image" width="800" height="1343" loading="lazy">
_Having a sleek front end is key in creating popular websites. Photo by [Unsplash](https://unsplash.com/photos/V09Io5ln-Qo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Aaron Huber on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-front-end-engineer">Front end engineer</h3>
<p><strong>What do they do?</strong></p>
<p>Front end engineers use HTML, CSS and JavaScript to build UI for websites. They focus on aspects that are important to the website such as accessibility, security, usability and performance. If you’ve ever logged into a website or bought something from an e-commerce store on your web browser, then you’ve interacted with a front end engineer’s code. <a target="_blank" href="https://medium.freecodecamp.org/my-role-as-a-front-end-web-engineer-explained-948d0f1ceac1">Check out this awesome article</a> for even more details.</p>
<p><strong>Why should I choose this career path?</strong></p>
<p>In a lot of ways, this job is similar to a mobile engineer’s job. They both build UI and should have a certain attention to detail when it comes to visual elements. They both work with designers to implement UI that is both performant and a delight to use. The main difference would be the languages and tools used and the fact that mobile developers are creating applications instead of websites.</p>
<p><strong>You should be a front end engineer if you are the kind of person that likes learning and using new languages and tech stacks</strong>. Being a front end engineer requires the use of HTML, CSS, JavaScript and SQL. On top of that, you will most likely need to know some back end server-side framework like Django, Ruby on Rails, or .Net.</p>
<p>Another reason to consider this path is if you are interested in problems around scaling. A mobile application will only ever serve one user at a time. This is due to the fact that only one person can use a mobile device at a time. A website has to serve potentially millions of people at the same time. This requires a different mindset and approach to prevent bottlenecks from occurring.</p>
<p><strong>How do I get started?</strong></p>
<p>This one is easy :) Just <a target="_blank" href="https://learn.freecodecamp.org/">checkout freeCodeCamp’s course</a>. This will give you all the skills you need to become a proficient front end engineer.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Msen2gjqJuczr8xpH2q9txROYvhiiWRSnjwH" alt="Image" width="800" height="533" loading="lazy">
_From committed code to delivery to production, a DevOps engineer has got you covered. Photo by [Unsplash](https://unsplash.com/photos/0wsnJWonXFs?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Drew Beamer on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-devops-engineer">DevOps Engineer</h3>
<p><strong>What do they do?</strong></p>
<p>This is by far the hardest role to explain. Because there is a lot of debate about whether this is really a role or actually just a mindset. The idea can be broken down into the fact that a DevOps engineer takes on both a developer and an operations job. Hence the term “DevOps”. Let’s look at each of these roles.</p>
<p>In general, software engineers want to build as many features as possible so they will look good to the higher ups. One of those new fancy features is bound to help the company grow which makes the software engineer look good.</p>
<p>An operations engineer wants stability. Which means they don’t want software engineers to release too many new features. Because with new features comes unpredictability. And with unpredictability, comes instability. The operations engineer just wants every new release to be stable. They want the release process to go smoothly. But releasing too many features or features of high risk threatens this goal, which is exactly what most software engineers are aiming to do.</p>
<p>These two roles obviously seem at odds but that is why a DevOps engineer can be so useful. <strong>A DevOps engineer can bridge the gap between development and operations</strong>. By doing this, they create meaningful communication routes between these sometimes silo-ed areas. A DevOps engineer creates a feature and sees it safely to production where it makes users satisfied. Being able to do this is highly valued at any company.</p>
<p><strong>Why should I choose this career path?</strong></p>
<p>You should choose this career path if you are not only interested in coding features, but want to learn about how to release your code to a production environment. You should have the drive to learn about every aspect of software engineering and release engineering.</p>
<p>You will most likely need years of experience to be termed as a “DevOps” engineer due to the vast amount of knowledge and tools you will need to learn. You should love learning new things. The idea of knowing every aspect of your tech stack should excite you. If you want to become the person that everyone goes to when something unexpected happens, then you should look into becoming a DevOps engineer.</p>
<p><strong>How do I get started?</strong></p>
<p>I’d get started by learning about how code gets released into a production environment for starters. This can be done by building your own website, and deploying it yourself. The best way is to work for a company for a while and work on every part of the deployment process. Volunteer to fix problems that others don’t want to deal with. That is a great way to learn.</p>
<p>Other than that, I’d recommend reading <a target="_blank" href="https://medium.com/@devfire/how-to-become-a-devops-engineer-in-six-months-or-less-366097df7737">this article on how to get into DevOps</a>. It is very well written gives even more actionable ways to become a DevOps engineer.</p>
<h3 id="heading-didnt-see-the-role-you-were-looking-for">Didn’t see the role you were looking for?</h3>
<p>If you enjoyed my summaries of these roles but didn’t see the role that you wanted, leave a comment! I will do another round of these career path overviews for the most clapped comments. Hopefully you enjoyed these summaries of these tech career paths. My hope is that you at least have a better understanding of the breadth of skills and knowledge it takes to release good tech to the world.</p>
<h4 id="heading-i-will-do-another-round-of-these-career-path-overviews-for-the-most-clapped-comments">I will do another round of these career path overviews for the most clapped comments.</h4>
<h3 id="heading-liked-what-you-read">Liked what you read?</h3>
<p><a target="_blank" href="https://medium.freecodecamp.org/how-i-went-from-stuck-and-hopeless-to-making-my-tech-career-dreams-come-true-d1fcf52c0650">Read about how I went from being a broke English teacher in Japan to working at a top tech company in just a few years!</a></p>
<p><a target="_blank" href="https://medium.freecodecamp.org/a-computer-science-degree-ticket-to-your-dream-tech-job-or-a-useless-piece-of-paper-ee488d27c384">Do you need a computer science degree to get a job in tech?</a></p>
<p><a target="_blank" href="https://medium.com/@colin.gabriel.smith/killing-it-during-your-first-tech-interview-16ce13f9d0ce">Passing your first tech interview: how to prepare.</a></p>
<p><a target="_blank" href="https://medium.freecodecamp.org/https-medium-com-colin-gabriel-smith-swift-vs-objective-c-5b19add8e2ed">Swift vs. Objective-C. How do they compare?</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ McDonald’s and Starbucks on Your Phone: Why Mobile Apps Are Now First on the Menu ]]>
                </title>
                <description>
                    <![CDATA[ By James Hsu One Friday this July, I got excited about McDonald's. So excited that I stopped at one before work in the morning and left with French fries and a coffee. Fries for breakfast. McDonald's had just announced that it would be giving out fre... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-mcdonalds-starbucks-are-all-in-on-native-mobile-apps-2faabc85b719/</link>
                <guid isPermaLink="false">66c366f2693ce41cd86e79a6</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ business ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ UX ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 24 Sep 2018 19:26:35 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*1qbKDuvqatJLhK_dSN8wlg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By James Hsu</p>
<p>One Friday this July, I got <em>excited</em> about McDonald's. So excited that I stopped at one before work in the morning and left with French fries and a coffee.</p>
<p>Fries for breakfast.</p>
<p>McDonald's had just announced that it would be giving out free medium fries every Friday with a minimum purchase of $1 through…</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Apple Pay Works Under the Hood ]]>
                </title>
                <description>
                    <![CDATA[ By Dumindu Buddhika Do you use Apple Pay? Have you ever wondered how an Apple Pay transaction goes through? In this post, you will learn how Apple Pay works end to end. Mobile payments have become very popular due to the convenience and the security ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-apple-pay-works-under-the-hood-8c3978238324/</link>
                <guid isPermaLink="false">66c34cd10fa3812cdd5ea9e6</guid>
                
                    <category>
                        <![CDATA[ Apple ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iphone ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 07 May 2018 06:29:56 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*Zsr_ysZ5bNXXnzdC0LHY6w.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dumindu Buddhika</p>
<p>Do you use Apple Pay? Have you ever wondered how an Apple Pay transaction goes through? In this post, you will learn how Apple Pay works end to end.</p>
<p>Mobile payments have become very popular due to the convenience and the security they offer. No more plastic cards to carry around, and you do not have to worry about losing them (what a relief!).</p>
<p>In this article, I am going to discuss how Apple Pay works in general and how it works when it is used at a physical POS terminal, specifically. I’ll briefly discuss the security benefits as well.</p>
<p>Before diving in, let’s get familiar with some basic terminology.</p>
<h4 id="heading-secure-element">Secure Element</h4>
<p>A secure element (SE) is something that is mentioned when talking about Apple Pay, so we need to understand what it is.</p>
<p>According to <a target="_blank" href="https://www.globalplatform.org/mediaguideSE.asp">Global Platform</a>:</p>
<blockquote>
<p>A Secure Element (SE) is a tamper-resistant platform (typically a one chip secure microcontroller) capable of securely hosting applications and their confidential and cryptographic data (e.g. key management) in accordance with the rules and security requirements set forth by a set of well-identified trusted authorities.</p>
</blockquote>
<p>Apple Pay uses SE to store secret information associated with tokenized cards (we will talk about this later).</p>
<p>In the iPhones after iPhone 6, and in Apple Watch, an SE is embedded into the device’s near-field communication (NFC) chip. This is used at payment terminals to perform transactions over NFC. SE emulates a payment card during an Apple Pay transaction.</p>
<h4 id="heading-tokenization">Tokenization</h4>
<p>Tokenization as a process is being adopted more and more in the payments industry. Here we’ll try to understand the basics of Tokenization.</p>
<p>The following is a concise description from Wikipedia on Tokenization technology:</p>
<blockquote>
<p><strong>Tokenization</strong>, when applied to data security, is the process of substituting a sensitive data element with a non-sensitive equivalent, referred to as a token, that has no extrinsic or exploitable meaning or value. The token is a reference (i.e. identifier) that maps back to the sensitive data through a tokenization system. The mapping from original data to a token uses methods which render tokens infeasible to reverse in the absence of the tokenization system</p>
</blockquote>
<p>In the context of credit cards and Apple Pay, <strong>tokenization</strong> is used to replace the Primary Account Number (PAN, or the credit card number) with a token. A token looks like a normal credit card number, but it’s not the original PAN. Tokenization stops the original card number from being used during transactions.</p>
<p>Tokens have no meaning by themselves and are worthless to criminals if a token is stolen. There is no algorithm to derive the Primary Account Number if you have a token. This makes it impossible for criminals to reverse engineer the Primary Account Number from a token.</p>
<p>Click <a target="_blank" href="https://en.wikipedia.org/wiki/Tokenization">here</a> for the Wikipedia article on tokenization if you want to learn more.</p>
<p>The following diagram describes the transaction flow of Apple Pay. We will discuss these step by step in the coming sections.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Tvs9gM2jDlgnFkUqWnw7f7bE1YG4DsYEsJah" alt="Image" width="613" height="518" loading="lazy">
<em>ymedialabs.com</em></p>
<h3 id="heading-adding-a-card-to-apple-pay">Adding a Card to Apple Pay</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/C4FQQR5WKo8KpyiLxfG3tvmsLRwiaOv6h5ny" alt="Image" width="274" height="396" loading="lazy">
_[http://www.iphoneincanada.ca](http://www.iphoneincanada.ca" rel="noopener" target="<em>blank" title=")</em></p>
<p>A card can be added to Apple Pay by either scanning the card or by submitting the card information. Then this information is submitted to Apple servers.</p>
<p>Apple sends the received card information to the relevant card network (Visa, MasterCard, AmericanExpress, Discover, and so on). Then the card network validates the card information with the issuing bank.</p>
<p>After the validation, the card network acting as a <a target="_blank" href="https://www.slideshare.net/bellidcom/what-is-a-token-service-provider-52887269">TSP</a> (Token Service Provider) creates a token (which is called a DAN or a Device Account Number in the context of Apple Pay) and a token key. This DAN is generated using tokenization and is not the actual card number.</p>
<p>Afterward, this information is sent back to Apple servers. After the device receives this information from Apple servers, it is saved in the device’s secure element (SE).</p>
<h3 id="heading-initiating-a-transaction-using-apple-pay">Initiating a Transaction Using Apple Pay</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/fzP2zrOr4FBQoNSAervf20OXqrWoeIHJhZHi" alt="Image" width="154" height="313" loading="lazy">
<em>support.apple.com</em></p>
<p>When you use your Apple device at a POS terminal to make a payment, the device communicates with the terminal to initiate a transaction. Apple Pay uses EMVCO’s <a target="_blank" href="https://www.emvco.com/emv-technologies/contactless/">contactless specification</a> to communicate with the terminal. If the terminal does not support EMV contactless, Apple Pay falls back to use contactless MSD (magnetic stripe data) mode.</p>
<h4 id="heading-emv-contactless-mode">EMV Contactless mode</h4>
<p>When EMV contactless mode is used, the Apple device communicates with the terminal according to the EMV contactless <a target="_blank" href="https://www.emvco.com/emv-technologies/contactless/">specification</a>. The secure element on the device generates a <strong>dynamic cryptogram</strong> for each transaction using the token, token key, amount, and other information related to the transaction. This dynamic cryptogram is then sent to the payment processor along with the token (DAN), transaction amount, and other required information to process the transaction.</p>
<h4 id="heading-contactless-msd-mode">Contactless MSD mode</h4>
<p>Contactless MSD exists to support terminals which are still not able to process using EMV contactless mode. Most of the terminals are still operating using contactless MSD mode. Let’s take a deeper look at how a transaction goes through using contactless MSD mode.</p>
<p>MSD, or Magnetic Stripe Data, is how older cards store card details. Data is stored as <strong>tracks</strong> in magnetic stripe cards. Magnetic stripe cards can have up to 3 tracks, and each track (track1, track2, track3) has a different format. Please click <a target="_blank" href="https://en.wikipedia.org/wiki/ISO/IEC_7813">here</a> for additional information on track data.</p>
<p>In Apple Pay contactless MSD mode, the track2 data format is used to transfer the card data to the payment processor which then communicates with the card network.</p>
<p>Let’s take a look at some example track data sent from a terminal to the processor for an Apple Pay transaction.</p>
<p>370295292756481=220672716078290600047</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/06Uue0GUDG01OBeKpoIeOHee0WRnfRdPm-mP" alt="Image" width="313" height="23" loading="lazy"></p>
<p>Above is an example of track data received from a terminal which was captured at a payment gateway.</p>
<p>Let’s understand this data segment by segment,</p>
<ul>
<li>Highlighted in yellow - This is the Device Account Number or the DAN (The example DAN here is from an AmericanExpress card. You can validate the bank identification number (BIN), or initial 6 digits in the credit card number, <a target="_blank" href="https://www.bincodes.com/bin-checker/">here</a>).</li>
<li>Highlighted in blue - This is the credit card expiry year and month(yy/mm)</li>
<li>Highlighted in pink - This is the service code. Click <a target="_blank" href="https://atlassian.idtechproducts.com/confluence/display/KB/Credit+Card+Service+Code+Chart++">here</a> to understand more about this.</li>
<li>Highlighted in purple - This part of data is discretionary to the card network. In case of Apple Pay, this is used as a <strong>dynamic card verification value (CVV).</strong></li>
</ul>
<p>We learned that in the EMV mode a <strong>dynamic cryptogram</strong> is generated. Here the <strong>dynamic CVV</strong> plays the role of the cryptogram. This is generated using the token key and other transaction-related data (similar to the generation of a <strong>dynamic cryptogram</strong>).</p>
<p>The track data shown above is sent to the <a target="_blank" href="https://en.wikipedia.org/wiki/Acquiring_bank">acquirer</a> along with the transaction amount. The acquirer forwards this information to the relevant card network (Visa, MasterCard, and so on ) based on the <a target="_blank" href="https://www.investopedia.com/terms/b/bank-identification-number.asp">BIN</a>.</p>
<h3 id="heading-completion-of-an-apple-pay-transaction">Completion of an Apple Pay Transaction</h3>
<p>When the card network receives the transaction request, it identifies whether it’s an actual card number or a tokenized card number. If it is tokenized (which is the case for Apple Pay transactions), the card network validates the cryptogram (or dynamic CVV) using their copy of the <strong>token key</strong> (the card network is acting as a <a target="_blank" href="https://www.slideshare.net/bellidcom/what-is-a-token-service-provider-52887269">TSP</a> here).</p>
<p>After some other additional validations, the card network de-tokenizes the DAN and obtains the original PAN (primary account number).</p>
<p>This transaction request is sent to the <a target="_blank" href="https://www.thebalance.com/credit-card-issuer-959984">issuer</a> (the bank or the financial institution who issued the credit card) along with the original PAN. The issuer authorizes the transaction and sends back the response which eventually reaches the POS terminal.</p>
<p>Yay! Transaction complete!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/QLw4aphNtbO5blklWMB-m9S2UsU5XWY7d63z" alt="Image" width="160" height="326" loading="lazy">
<em>support.apple.com</em></p>
<h3 id="heading-replaying-transaction-requests">Replaying Transaction Requests</h3>
<p>One of the biggest problems with the traditional card transactions is the ability to replay past transaction requests (<a target="_blank" href="https://en.wikipedia.org/wiki/Replay_attack">replay attack</a>). If you resend the same transaction request, another transaction would be done with the same data.</p>
<p>With Apple Pay, this does not happen (also when using EMV cards directly on the terminal as well). Every transaction request can only be used once. The dynamic cryptogram (dynamic CVV in MSD mode) ensures this. For each transaction, a new cryptogram is generated which can only be used once (and is only valid for a certain time period).</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this article, we have gone through an overview of the Apple Pay transaction flow. I will discuss Google Pay in a coming article.</p>
<h4 id="heading-references">References</h4>
<ul>
<li><a target="_blank" href="http://www.gmarwaha.com/blog/2015/01/03/apple-pay-an-attempt-to-demystify-take-2/">http://www.gmarwaha.com/blog/2015/01/03/apple-pay-an-attempt-to-demystify-take-2/</a></li>
<li><a target="_blank" href="https://www.emvco.com/emv-technologies/contactless/">https://www.emvco.com/emv-technologies/contactless/</a></li>
<li><a target="_blank" href="http://msrtron.com/blog-headlines/blog-card-data">http://msrtron.com/blog-headlines/blog-card-data</a></li>
<li><a target="_blank" href="https://www.slideshare.net/bellidcom/what-is-a-token-service-provider-52887269">https://www.slideshare.net/bellidcom/what-is-a-token-service-provider-52887269</a></li>
</ul>
<h4 id="heading-before-you-go">Before you go!</h4>
<p>If you have enjoyed this article, claps are welcome!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A guide to getting the most out of the Push API ]]>
                </title>
                <description>
                    <![CDATA[ Interested in learning JavaScript? Get my ebook at jshandbook.com The Push API allows a web app to receive messages pushed by a server, even if the web app is not currently open in the browser or not running on the device. The Push API is a recent a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-guide-to-getting-the-most-out-of-the-push-api-72a139bfeb44/</link>
                <guid isPermaLink="false">66bb5a4b52dd937e26c971ea</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Flavio Copes ]]>
                </dc:creator>
                <pubDate>Sat, 07 Apr 2018 02:39:53 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*zhjnyEri0hw-WNu2dLLgmg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <blockquote>
<p>Interested in learning JavaScript? Get my ebook at <a target="_blank" href="https://jshandbook.com/">jshandbook.com</a></p>
</blockquote>
<p>The Push API allows a web app to receive messages pushed by a server, even if the web app is not currently open in the browser or not running on the device.</p>
<p>The Push API is a recent addition to browser APIs, and it’s currently supported by Chrome (Desktop and Mobile), Firefox, and Opera since 2016.</p>
<p>IE and Edge do not support it yet, and Safari <a target="_blank" href="https://developer.apple.com/notifications/safari-push-notifications/">has its own implementation</a> of it. Since Chrome and Firefox support it, approximately 60% of users browsing on their desktops have access to it, so it’s quite safe to use.</p>
<h3 id="heading-what-can-you-do-with-it">What can you do with it</h3>
<p>You can send messages to your users, pushing them from the server to the client, even when the user is not browsing the site.</p>
<p>This lets you deliver notifications and content updates, giving you the ability to engage more with your audience.</p>
<p>This is huge, because one of the missing pillars of the mobile web, compared to native apps, used to be the ability to receive notifications, along with offline support.</p>
<h3 id="heading-how-it-works">How it works</h3>
<p>When a user visits your web app, you can trigger a panel asking permission to send updates. A <a target="_blank" href="https://flaviocopes.com/service-workers">Service Worker</a> is installed, and operates in the background listening for a <a target="_blank" href="https://flaviocopes.com/service-workers#push-events">Push Event</a>.</p>
<blockquote>
<p><em>Push and Notifications are two separate concepts and APIs. They’re sometimes mixed up because of the <strong>push notifications</strong> term used in iOS. Basically, the Notifications API is invoked when a push event is received using the Push API.</em></p>
</blockquote>
<p>Your <strong>server</strong> sends the notification to the client, and the Service Worker, if given permission, receives a <strong>push event</strong>. The Service Worker reacts to this event by <strong>triggering a notification</strong>.</p>
<h3 id="heading-getting-the-users-permission">Getting the user’s permission</h3>
<p>The first step in working with the Push API is getting the user’s permission to receive data from you.</p>
<blockquote>
<p><em>Many sites implement this panel badly, showing it on the first page load. The user is not yet convinced your content is good, and they will deny the permission. So do it wisely.</em></p>
</blockquote>
<p>There are six steps to getting permission from your user:</p>
<ol>
<li>Check if Service Workers are supported</li>
<li>Check if the Push API is supported</li>
<li>Register a Service Worker</li>
<li>Request permission from the user</li>
<li>Subscribe the user and get the PushSubscription object</li>
<li>Send the PushSubscription object to your server</li>
</ol>
<p>Let’s go through them one by one.</p>
<h3 id="heading-check-if-service-workers-are-supported">Check if Service Workers are supported</h3>
<pre><code><span class="hljs-keyword">if</span> (!(<span class="hljs-string">'serviceWorker'</span> <span class="hljs-keyword">in</span> navigator)) {  <span class="hljs-comment">// Service Workers are not supported. Return  return}</span>
</code></pre><h3 id="heading-check-if-the-push-api-is-supported">Check if the Push API is supported</h3>
<pre><code><span class="hljs-keyword">if</span> (!(<span class="hljs-string">'PushManager'</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">window</span>)) {  <span class="hljs-comment">// The Push API is not supported. Return  return}</span>
</code></pre><h3 id="heading-register-a-service-worker">Register a Service Worker</h3>
<p>This code registers the Service Worker located in the <code>worker.js</code> file placed in the domain root:</p>
<pre><code><span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'load'</span>, <span class="hljs-function">() =&gt;</span> {  navigator.serviceWorker.register(<span class="hljs-string">'/worker.js'</span>)  .then(<span class="hljs-function">(<span class="hljs-params">registration</span>) =&gt;</span> {    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Service Worker registration completed with scope: '</span>,      registration.scope)  }, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Service Worker registration failed'</span>, err)  })})
</code></pre><p>To know more about how Service Workers work in detail, check out the <a target="_blank" href="https://flaviocopes.com/service-workers">Service Workers guide</a>.</p>
<h3 id="heading-request-permission-from-the-user">Request permission from the user</h3>
<p>Now that the Service worker is registered, you can request the permission.</p>
<p>The API to do this has changed over time, and it went from accepting a callback function as a parameter to returning a <a target="_blank" href="https://flaviocopes.com/javascript-promises/">Promise</a>, breaking the backward and forward compatibility. And note that we need to do <strong>both,</strong> as we don’t know which approach is implemented by the user’s browser.</p>
<p>The code is the following, calling <code>Notification.requestPermission()</code>.</p>
<pre><code><span class="hljs-keyword">const</span> askPermission = <span class="hljs-function">() =&gt;</span> {  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {    <span class="hljs-keyword">const</span> permissionResult = Notification.requestPermission(      <span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {        resolve(result)      }    )    <span class="hljs-keyword">if</span> (permissionResult) {      permissionResult.then(resolve, reject)    }  })  .then(<span class="hljs-function">(<span class="hljs-params">permissionResult</span>) =&gt;</span> {    <span class="hljs-keyword">if</span> (permissionResult !== <span class="hljs-string">'granted'</span>) {      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Permission denied'</span>)    }  })}
</code></pre><p>The <code>permissionResult</code> value is a string, that can have the value of: - <code>granted</code> - <code>default</code> - <code>denied</code></p>
<p>This code causes the browser to show the permission dialogue:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/S3HKfHLPj2Vg24jR3u0m0letQehHJjKwcqZ0" alt="Image" width="537" height="160" loading="lazy"></p>
<p><strong>If the user clicks Block, you won’t be able to ask for the user’s permission any more</strong>, unless they manually go and unblock the site in an advanced settings panel in the browser (very unlikely to happen).</p>
<p>If the user gave us permission, we can subscribe them by calling <code>registration.pushManager.subscribe()</code>.</p>
<pre><code><span class="hljs-keyword">const</span> APP_SERVER_KEY = <span class="hljs-string">'XXX'</span><span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'load'</span>, <span class="hljs-function">() =&gt;</span> {  navigator.serviceWorker.register(<span class="hljs-string">'/worker.js'</span>)  .then(<span class="hljs-function">(<span class="hljs-params">registration</span>) =&gt;</span> {    askPermission().then(<span class="hljs-function">() =&gt;</span> {      <span class="hljs-keyword">const</span> options = {        <span class="hljs-attr">userVisibleOnly</span>: <span class="hljs-literal">true</span>,        <span class="hljs-attr">applicationServerKey</span>: urlBase64ToUint8Array(APP_SERVER_KEY)      }      <span class="hljs-keyword">return</span> registration.pushManager.subscribe(options)    }).then(<span class="hljs-function">(<span class="hljs-params">pushSubscription</span>) =&gt;</span> {      <span class="hljs-comment">// we got the pushSubscription object    }  }, (err) =&gt; {    console.log('Service Worker registration failed', err)  })})</span>
</code></pre><p><code>APP_SERVER_KEY</code> is a string — called <em>Application Server Key</em> or <em>VAPID key</em> — that identifies the applications’s public key, part of a public / private key pair.</p>
<p>It will be used as part of the validation that, for security reasons, comes up to make sure you (and only you, not someone else) can send a push message back to the user.</p>
<h3 id="heading-send-the-pushsubscription-object-to-your-server">Send the PushSubscription object to your server</h3>
<p>In the previous snippet we got the <code>pushSubscription</code> object, which contains all we need to send a push message to the user. We need to send this information to our server so we’re able to send notifications later on.</p>
<p>We first create a JSON representation of the object</p>
<pre><code><span class="hljs-keyword">const</span> subscription = <span class="hljs-built_in">JSON</span>.stringify(pushSubscription)
</code></pre><p>and we can post it to our server using the <a target="_blank" href="https://flaviocopes.com/fetch-api">Fetch API</a>:</p>
<pre><code><span class="hljs-keyword">const</span> sendToServer = <span class="hljs-function">(<span class="hljs-params">subscription</span>) =&gt;</span> {  <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">'/api/subscription'</span>, {    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,    <span class="hljs-attr">headers</span>: {      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>    },    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(subscription)  })  .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {    <span class="hljs-keyword">if</span> (!res.ok) {      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'An error occurred'</span>)    }    <span class="hljs-keyword">return</span> res.json()  })  .then(<span class="hljs-function">(<span class="hljs-params">resData</span>) =&gt;</span> {    <span class="hljs-keyword">if</span> (!(resData.data &amp;&amp; resData.data.success)) {      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'An error occurred'</span>)    }  })}sendToServer(subscription)
</code></pre><p>Server-side, the <code>/api/subscription</code> endpoint receives the POST request and can store the subscription information into its storage.</p>
<h3 id="heading-how-the-server-side-works">How the Server side works</h3>
<p>So far we only talked about the client-side part: getting a user’s permission to be notified in the future.</p>
<p>What about the server? What should it do, and how should it interact with the client?</p>
<blockquote>
<p><em>These server-side examples use <a target="_blank" href="http://expressjs.com/">Express.js</a> as the base HTTP framework, but you can write a server-side Push API handler in any language or framework</em></p>
</blockquote>
<h3 id="heading-registering-a-new-client-subscription">Registering a new client subscription</h3>
<p>When the client sends a new subscription, remember that we used the <code>/api/subscription</code> HTTP POST endpoint, sending the PushSubscription object details in JSON format, in the body.</p>
<p>We initialize Express.js:</p>
<pre><code><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)<span class="hljs-keyword">const</span> app = express()
</code></pre><p>This utility function makes sure the request is valid and has a body and an endpoint property, otherwise it returns an error to the client:</p>
<pre><code><span class="hljs-keyword">const</span> isValidSaveRequest = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {  <span class="hljs-keyword">if</span> (!req.body || !req.body.endpoint) {    res.status(<span class="hljs-number">400</span>)    res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/json'</span>)    res.send(<span class="hljs-built_in">JSON</span>.stringify({      <span class="hljs-attr">error</span>: {        <span class="hljs-attr">id</span>: <span class="hljs-string">'no-endpoint'</span>,        <span class="hljs-attr">message</span>: <span class="hljs-string">'Subscription must have an endpoint'</span>      }    }))    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>  }  <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>}
</code></pre><p>The next utility function saves the subscription to the database, returning a promise resolved when the insertion completed (or failed). The <code>insertToDatabase</code> function is a placeholder — we’re not going into those details here:</p>
<pre><code><span class="hljs-keyword">const</span> saveSubscriptionToDatabase = <span class="hljs-function">(<span class="hljs-params">subscription</span>) =&gt;</span> {  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {    insertToDatabase(subscription, <span class="hljs-function">(<span class="hljs-params">err, id</span>) =&gt;</span> {      <span class="hljs-keyword">if</span> (err) {        reject(err)        <span class="hljs-keyword">return</span>      }      resolve(id)    })  })}
</code></pre><p>We use those functions in the POST request handler below. We check if the request is valid, then we save the request and return a <code>data.success: true</code> response back to the client, or an error:</p>
<pre><code>app.post(<span class="hljs-string">'/api/subscription'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {  <span class="hljs-keyword">if</span> (!isValidSaveRequest(req, res)) {    <span class="hljs-keyword">return</span>  }  saveSubscriptionToDatabase(req, res.body)  .then(<span class="hljs-function">(<span class="hljs-params">subscriptionId</span>) =&gt;</span> {    res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/json'</span>)    res.send(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">data</span>: { <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> } }))  })  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {    res.status(<span class="hljs-number">500</span>)    res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/json'</span>)    res.send(<span class="hljs-built_in">JSON</span>.stringify({      <span class="hljs-attr">error</span>: {        <span class="hljs-attr">id</span>: <span class="hljs-string">'unable-to-save-subscription'</span>,        <span class="hljs-attr">message</span>: <span class="hljs-string">'Subscription received but failed to save it'</span>      }    }))  })})app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'App listening on port 3000'</span>)})
</code></pre><h3 id="heading-sending-a-push-message">Sending a Push message</h3>
<p>Now that the server has registered the client in its list, we can send it Push messages. Let’s see how that works by creating an example code snippet that fetches all subscriptions and sends a Push message to all of them at the same time.</p>
<p>We use a library because the <a target="_blank" href="https://developers.google.com/web/fundamentals/push-notifications/web-push-protocol"><strong>Web Push protocol</strong></a> is complex, and a lib allows us to abstract away a lot of low level code that makes sure we can work safely and can correctly handle any edge case.</p>
<blockquote>
<p><em>This example uses the <code>web-push</code> <a target="_blank" href="https://flaviocopes.com/nodejs/">Node.js</a> <a target="_blank" href="https://github.com/web-push-libs/web-push">library</a> to handle sending the Push message.</em></p>
</blockquote>
<p>We first initialize the <code>web-push</code> lib, and we generate a tuple of private and public keys, and set them as the VAPID details:</p>
<pre><code><span class="hljs-keyword">const</span> webpush = <span class="hljs-built_in">require</span>(<span class="hljs-string">'web-push'</span>)<span class="hljs-keyword">const</span> vapidKeys = webpush.generateVAPIDKeys()<span class="hljs-keyword">const</span> PUBLIC_KEY = <span class="hljs-string">'XXX'</span><span class="hljs-keyword">const</span> PRIVATE_KEY = <span class="hljs-string">'YYY'</span><span class="hljs-keyword">const</span> vapidKeys = {  <span class="hljs-attr">publicKey</span>: PUBLIC_KEY,  <span class="hljs-attr">privateKey</span>: PRIVATE_KEY}webpush.setVapidDetails(  <span class="hljs-string">'mailto:my@email.com'</span>,  vapidKeys.publicKey,  vapidKeys.privateKey)
</code></pre><p>Then we set up a <code>triggerPush()</code> method, responsible for sending the push event to a client. It just calls <code>webpush.sendNotification()</code> and catches any error. If the return error HTTP status code is <a target="_blank" href="https://developer.mozilla.org/docs/Web/HTTP/Status/410">410</a>, which means <strong>gone</strong>, we delete that subscriber from the database.</p>
<pre><code><span class="hljs-keyword">const</span> triggerPush = <span class="hljs-function">(<span class="hljs-params">subscription, dataToSend</span>) =&gt;</span> {  <span class="hljs-keyword">return</span> webpush.sendNotification(subscription, dataToSend)  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {    <span class="hljs-keyword">if</span> (err.statusCode === <span class="hljs-number">410</span>) {      <span class="hljs-keyword">return</span> deleteSubscriptionFromDatabase(subscription._id)    } <span class="hljs-keyword">else</span> {      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Subscription is no longer valid: '</span>, err)    }  })}
</code></pre><p>We don’t implement getting the subscriptions from the database, but we leave it as a stub:</p>
<pre><code><span class="hljs-keyword">const</span> getSubscriptionsFromDatabase = <span class="hljs-function">() =&gt;</span> {  <span class="hljs-comment">//stub}</span>
</code></pre><p>The meat of the code is the callback of the POST request to the <code>/api/push</code> endpoint:</p>
<pre><code>app.post(<span class="hljs-string">'/api/push'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {  <span class="hljs-keyword">return</span> getSubscriptionsFromDatabase()  .then(<span class="hljs-function">(<span class="hljs-params">subscriptions</span>) =&gt;</span> {    <span class="hljs-keyword">let</span> promiseChain = <span class="hljs-built_in">Promise</span>.resolve()    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; subscriptions.length; i++) {      <span class="hljs-keyword">const</span> subscription = subscriptions[i]      promiseChain = promiseChain.then(<span class="hljs-function">() =&gt;</span> {        <span class="hljs-keyword">return</span> triggerPush(subscription, dataToSend)      })    }    <span class="hljs-keyword">return</span> promiseChain  })  .then(<span class="hljs-function">() =&gt;</span> {    res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/json'</span>)    res.send(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">data</span>: { <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> } }))  })  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {    res.status(<span class="hljs-number">500</span>)    res.setHeader(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/json'</span>)    res.send(<span class="hljs-built_in">JSON</span>.stringify({      <span class="hljs-attr">error</span>: {        <span class="hljs-attr">id</span>: <span class="hljs-string">'unable-to-send-messages'</span>,        <span class="hljs-attr">message</span>: <span class="hljs-string">`Failed to send the push <span class="hljs-subst">${err.message}</span>`</span>      }    }))  })})
</code></pre><p>The above code gets all the subscriptions from the database, then it iterates on them, and it calls the <code>triggerPush()</code> function we explained before.</p>
<p>Once the subscriptions are done, we return a successful JSON response. Unless an error occurred, and then we return a 500 error.</p>
<h3 id="heading-in-the-real-world">In the real world…</h3>
<p>It’s unlikely that you’ll set up your own Push server unless you have a very special use case, or you just want to learn the tech or you like to DIY.</p>
<p>Instead, you’ll usually want to use platforms such as <a target="_blank" href="https://onesignal.com">OneSignal</a> which transparently handle Push events to all kind of platforms, Safari and iOS included, for free.</p>
<h3 id="heading-receive-a-push-event">Receive a Push event</h3>
<p>When a Push event is sent from the server, how does the client get it?</p>
<p>It’s a normal JavaScript event listener, on the <code>push</code> event, which runs inside a Service Worker:</p>
<pre><code>self.addEventListener(<span class="hljs-string">'push'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {  <span class="hljs-comment">// data is available in event.data})</span>
</code></pre><p><code>event.data</code> contains the <code>[PushMessageData](https://developer.mozilla.org/docs/Web/API/PushMessageData)</code> object which exposes methods to retrieve the push data sent by the server, in the format you want:</p>
<ul>
<li><strong>arrayBuffer()</strong> : as an ArrayBuffer object</li>
<li><strong>blob()</strong>: as a Blob object</li>
<li><strong>json()</strong>: parsed as JSON</li>
<li><strong>text()</strong>: plain text</li>
</ul>
<p>You’ll normally use <code>event.data.json()</code>.</p>
<h3 id="heading-displaying-a-notification">Displaying a notification</h3>
<p>Here we intersect a bit with the <a target="_blank" href="https://flaviocopes.com/notifications-api">Notifications API</a>, but for a good reason, as one of the main use cases of the Push API is to display notifications.</p>
<p>Inside our <code>push</code> event listener in the Service Worker, we need to display the notification to the user. We also need to tell the event to wait until the browser has shown it before the function can terminate. We extend the event lifetime until the browser has finished displaying the notification (until the promise has been resolved), otherwise the Service Worker could be stopped in the middle of your processing:</p>
<pre><code>self.addEventListener(<span class="hljs-string">'push'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {  <span class="hljs-keyword">const</span> promiseChain = self.registration.showNotification(<span class="hljs-string">'Hey!'</span>)  event.waitUntil(promiseChain)})
</code></pre><blockquote>
<p>Interested in learning JavaScript? Get my ebook at <a target="_blank" href="https://jshandbook.com/">jshandbook.com</a></p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
