Jekyll2022-05-06T20:38:24+00:00https://tim.klingeleers.be/feed.xmlTim Klingeleers BlogDeveloper blogTim KlingeleersQwik - an HTML first web approach2022-04-28T16:00:00+00:002022-04-28T16:00:00+00:00https://tim.klingeleers.be/2022/04/28/qwik-alternative-web-approach<p>Meet <a href="https://github.com/BuilderIO/qwik">Qwik</a>, I had never heard of it before, but bumped into it while browsing the web. It instantly sparked my interest by stating that it can deliver an instantly loaded web application, with an HTML-first approach. Another reason to look into it, is that it is created by Misko Hevery, the person who created AngularJS back in 2009.</p>
<p>Every once in a while you bump into a framework or tool, that takes a very different approach than you are used to. So let’s explore Qwik and what it does differently than the usual suspects.</p>
<!--more-->
<h3 id="qwik-whats-so-different">Qwik, what’s so different?</h3>
<p>Qwik uses a completely different mental model and philosophy, so it can be hard to grasp at first. But once you get the hang of it, this can be a game changer on how you look at other frameworks.</p>
<p>To find out what makes Qwik different from other frameworks like Angular or React, we need to explore a few concepts first. The most important concept is hydration and SSR (server side rendering), and what Qwik calls “resumability”.</p>
<p>In order to get an Angular application up and running, even with SSR, the server needs to render the HTML and make sure the client can render it. But to do that, it needs to load the complete framework and all components at the first load. Then it usually also needs a bunch of data via XHR requests. Module separation in Angular for example can decrease the load size a bit, based on routing. However, the framework, the root module and the current route module are the bare minimum that a client needs to become functional. This can be a fairly large chunk of code to load.</p>
<p>Resumability is the solution that Qwik uses to prevent hydration steps, and actually means that no Javascript is necessary to see a fully functional application on page load. The SSR makes sure that all HTML and data is included in the HTML itself.</p>
<h3 id="how-does-it-work">How does it work?</h3>
<p>Qwik loads a very minimal Qwikloader component that is 1kb in size and executes in 10ms or less. It also includes the necessary data in the HTML itself to save on roundtrips. Everything that is necessary to have a functional application will be loaded in this initial HTML, therefore no hydration on the client is necessary.</p>
<p>The Qwikloader can load very small bundles of Javascript as soon as the functionality is required. This does not happen on a page or route level, but on a component level. For example, when you click a button,only the code that is required to execute the button click is loaded and nothing more. There is a small caveat here, which is that a small delay in execution is possible when the download speed is very low.</p>
<h3 id="can-it-hold-up-to-its-premise">Can it hold up to its premise?</h3>
<p>The premise of Qwik is that regardless of application size, the loading time will always stay very minimal. Everything that is added to the framework is included with this in mind. This is a very strong concept when loading times are crucial for your application.</p>
<p>So as usual, it might be the right tool for some jobs but not for others. I encourage you to read the <a href="https://qwik.builder.io/guide/overview">Qwik guide</a> and familiarize yourself with it, so you can add it to your toolbelt if necessary.</p>
<p>I have not seen this in the wild just yet, so I have no proof on how well it can hold up in large scale applications. But if it can hold up to its premise, it has the potential to grow out to become the next big thing.</p>Tim KlingeleersMeet Qwik, I had never heard of it before, but bumped into it while browsing the web. It instantly sparked my interest by stating that it can deliver an instantly loaded web application, with an HTML-first approach. Another reason to look into it, is that it is created by Misko Hevery, the person who created AngularJS back in 2009. Every once in a while you bump into a framework or tool, that takes a very different approach than you are used to. So let’s explore Qwik and what it does differently than the usual suspects.Generating a markdown changelog from git2022-03-24T16:00:00+00:002022-03-24T16:00:00+00:00https://tim.klingeleers.be/2022/03/24/changelog-generation<p>When you make use commit formats like <a href="https://www.conventionalcommits.org/">conventional commits</a>, this standardisation can get you some useful benefits. In this scenario, I wanted to create a changelog in markdown format, that listed all of the bugfixes and features that were created per release and link to a JIRA ticket that is associated with it. Let’s take a look how this was achieved.</p>
<!--more-->
<h3 id="update">Update</h3>
<p>I recently found an open source project called <a href="https://github.com/orhun/git-cliff">git-cliff</a> that does something similar as written in this article, but in a better and more advanced way.</p>
<h3 id="our-requirements">Our requirements</h3>
<p>We wanted to generate a markdown file that included all features, bugfixes and chores for every release that we have in our git repository. These releases are marked with a tag. We are using JIRA for issue management and Azure DevOps for our git repository, and we want to link every commit to a JIRA ticket. The changelog should include a link to the JIRA ticket per commit, and a link that displays all code changes for a release to Azure DevOps per tag.</p>
<h3 id="using-git-and-tags">Using git and tags</h3>
<p>To start the generation process, a list of commits is needed in groups per tag. In this case it’s a fairly easy one, since we don’t use tags for anything else but to mark a release. Otherwise we could filter it by looking for a specific format (e.g. v#.#.#).</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">GIT_TAGS</span><span class="o">=</span><span class="si">$(</span>git tag <span class="nt">-l</span> <span class="nt">--sort</span><span class="o">=</span><span class="nt">-version</span>:refname<span class="si">)</span>
</code></pre></div></div>
<p>The list of tags that we get here is prepended with a <code class="language-plaintext highlighter-rouge">HEAD</code> “tag”, since we also want to list all of the unreleased commits.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">TAGS</span><span class="o">=(</span><span class="s2">"HEAD"</span><span class="o">)</span>
TAGS+<span class="o">=(</span><span class="nv">$GIT_TAGS</span><span class="o">)</span>
</code></pre></div></div>
<p>After we have all the tags, we can get a list of commit hashes between these tags, by making use of the <code class="language-plaintext highlighter-rouge">pretty-format</code> option. The commit hashes are the most important for further processing.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">[[</span> <span class="nt">-z</span> <span class="nv">$PREVIOUS_TAG</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">COMMITS</span><span class="o">=</span><span class="si">$(</span>git log <span class="nv">$LATEST_TAG</span> <span class="nt">--pretty</span><span class="o">=</span>format:<span class="s2">"%H"</span><span class="si">)</span>
<span class="k">else
</span><span class="nv">COMMITS</span><span class="o">=</span><span class="si">$(</span>git log <span class="nv">$PREVIOUS_TAG</span>..<span class="nv">$LATEST_TAG</span> <span class="nt">--pretty</span><span class="o">=</span>format:<span class="s2">"%H"</span><span class="si">)</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>Now that we have this list of commit hashes, we can loop over them and get specific details on the commit. Since we are using conventional commits, every commit title is prepended with a specific keyword depending on the type of change. The most important keywords that we use in the script are:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">feat:</code> when a new feature is created</li>
<li><code class="language-plaintext highlighter-rouge">fix:</code> when a bugfix is created</li>
<li><code class="language-plaintext highlighter-rouge">chore:</code> for something else</li>
</ul>
<p>All of the other keywords from the conventional commit format are discarded in our changelog.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Get the subject of the current commit</span>
<span class="nv">SUBJECT</span><span class="o">=</span><span class="si">$(</span>git log <span class="nt">-1</span> <span class="k">${</span><span class="nv">COMMIT</span><span class="k">}</span> <span class="nt">--pretty</span><span class="o">=</span>format:<span class="s2">"%s"</span><span class="si">)</span>
<span class="c"># Is it marked as a feature commit?</span>
<span class="nv">FEATURE</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s2">"feat:"</span> <span class="o"><<<</span><span class="s2">"</span><span class="nv">$SUBJECT</span><span class="s2">"</span><span class="si">)</span>
<span class="c"># Is it marked as a bugfix commit?</span>
<span class="nv">FIX</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s2">"fix:"</span> <span class="o"><<<</span><span class="s2">"</span><span class="nv">$SUBJECT</span><span class="s2">"</span><span class="si">)</span>
<span class="c"># Is it marked as a chore commit?</span>
<span class="nv">CHORE</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s2">"chore:"</span> <span class="o"><<<</span><span class="s2">"</span><span class="nv">$SUBJECT</span><span class="s2">"</span><span class="si">)</span>
</code></pre></div></div>
<p>Once we know if it is one of the previous types of commits, we can start dissecting the commit body and figure out if a JIRA ticket is referenced. In our team the convention is that the last JIRA ticket that is referenced in the commit body, is the main ticket for the commit.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Get the body of the commit</span>
<span class="nv">BODY</span><span class="o">=</span><span class="si">$(</span>git log <span class="nt">-1</span> <span class="k">${</span><span class="nv">COMMIT</span><span class="k">}</span> <span class="nt">--pretty</span><span class="o">=</span>format:<span class="s2">"%b"</span><span class="si">)</span>
<span class="c"># Does the body contain a link to a JIRA-number</span>
<span class="nv">JIRA_ID</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s2">"JIRA-[[:digit:]]+"</span> <span class="o"><<<</span><span class="nv">$BODY</span><span class="si">)</span>
<span class="c"># Get last JIRA-number of the body (body might reference others)</span>
<span class="nv">JIRA_ID</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$JIRA_ID</span><span class="s2">"</span> | <span class="nb">tail</span> <span class="nt">-1</span><span class="si">)</span>
</code></pre></div></div>
<p>If the commit body does not include a JIRA ticket number, we skip it from the changelog. Otherwise we add it to the correct list for the type of change.</p>
<p>The rest of the script is specific styling for our markdown file, that can be manipulated to your liking. In the example code, we start with a title and a latest update date. Then show a list of all unreleased changes, followed by all changes sorted by tag from new to old. The features are listed first, then the bugfixes and then the chores. Every tag is also ended by a link to get the same list in Azure DevOps.</p>
<h3 id="making-use-of-the-script-in-cicd">Making use of the script in CI/CD</h3>
<p>We can use the script in our CI/CD pipeline and get the markdown file. To make it even more useful for the product stakeholders, this markdown can be automatically converted to PDF for further distribution.</p>
<h3 id="full-script">Full script</h3>
<p>You’ll have to replace the <…> in the settings section with your own.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="nv">IFS</span><span class="o">=</span><span class="s1">$'</span><span class="se">\n</span><span class="s1">'</span>
<span class="c"># Settings</span>
<span class="nv">PRODUCT_NAME</span><span class="o">=</span><span class="s2">"My app"</span>
<span class="nv">REPOSITORY_URL</span><span class="o">=</span><span class="s2">"https://<jira-server>/browse"</span>
<span class="nv">AZURE_DEVOPS_GIT_URL</span><span class="o">=</span><span class="s2">"https://<tenant>.visualstudio.com/<project>/_git/<repository>"</span>
<span class="nv">INCLUDE_FEATURES</span><span class="o">=</span>1
<span class="nv">INCLUDE_FIXES</span><span class="o">=</span>1
<span class="nv">INCLUDE_CHORES</span><span class="o">=</span>1
<span class="c"># Get a list of all tags in reverse order</span>
<span class="nv">GIT_TAGS</span><span class="o">=</span><span class="si">$(</span>git tag <span class="nt">-l</span> <span class="nt">--sort</span><span class="o">=</span><span class="nt">-version</span>:refname<span class="si">)</span>
<span class="nv">DATE_NOW</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> <span class="s1">'+%d-%m-%Y'</span><span class="si">)</span>
<span class="c"># Add title</span>
<span class="nv">MARKDOWN</span><span class="o">=</span><span class="s2">"# Changelog </span><span class="k">${</span><span class="nv">PRODUCT_NAME</span><span class="k">}</span><span class="se">\n</span><span class="s2"><sup>Last updated: </span><span class="nv">$DATE_NOW</span><span class="s2"></sup></span><span class="se">\n\n</span><span class="s2">"</span>
<span class="c"># Make the tags an array and include HEAD as the first (so we can include unreleased changes)</span>
<span class="nv">TAGS</span><span class="o">=(</span><span class="s2">"HEAD"</span><span class="o">)</span>
TAGS+<span class="o">=(</span><span class="nv">$GIT_TAGS</span><span class="o">)</span>
<span class="k">for </span>TAG_INDEX <span class="k">in</span> <span class="s2">"</span><span class="k">${</span><span class="p">!TAGS[@]</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span> <span class="k">do
</span><span class="nv">FEATURES</span><span class="o">=()</span>
<span class="nv">FIXES</span><span class="o">=()</span>
<span class="nv">CHORES</span><span class="o">=()</span>
<span class="nv">LATEST_TAG</span><span class="o">=</span><span class="k">${</span><span class="nv">TAGS</span><span class="p">[TAG_INDEX]</span><span class="k">}</span>
<span class="nv">PREVIOUS_TAG</span><span class="o">=</span><span class="k">${</span><span class="nv">TAGS</span><span class="p">[TAG_INDEX + 1]</span><span class="k">}</span>
<span class="nv">TAG_DATE</span><span class="o">=</span><span class="si">$(</span>git <span class="k">for</span><span class="nt">-each-ref</span> <span class="nt">--format</span><span class="o">=</span><span class="s2">"%(taggerdate:format:%d-%m-%Y)"</span> <span class="s2">"refs/tags/</span><span class="k">${</span><span class="nv">LATEST_TAG</span><span class="k">}</span><span class="s2">"</span><span class="si">)</span>
<span class="c"># Get a log of commits that occured between two tags</span>
<span class="c"># We only get the commit hash so we don't have to deal with a bunch of ugly parsing</span>
<span class="c"># See Pretty format placeholders at https://git-scm.com/docs/pretty-formats</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nt">-z</span> <span class="nv">$PREVIOUS_TAG</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">COMMITS</span><span class="o">=</span><span class="si">$(</span>git log <span class="nv">$LATEST_TAG</span> <span class="nt">--pretty</span><span class="o">=</span>format:<span class="s2">"%H"</span><span class="si">)</span>
<span class="k">else
</span><span class="nv">COMMITS</span><span class="o">=</span><span class="si">$(</span>git log <span class="nv">$PREVIOUS_TAG</span>..<span class="nv">$LATEST_TAG</span> <span class="nt">--pretty</span><span class="o">=</span>format:<span class="s2">"%H"</span><span class="si">)</span>
<span class="k">fi</span>
<span class="c"># Loop over each commit and look for feature, bugfix or chore commits</span>
<span class="k">for </span>COMMIT <span class="k">in</span> <span class="nv">$COMMITS</span><span class="p">;</span> <span class="k">do</span>
<span class="c"># Get the subject of the current commit</span>
<span class="nv">SUBJECT</span><span class="o">=</span><span class="si">$(</span>git log <span class="nt">-1</span> <span class="k">${</span><span class="nv">COMMIT</span><span class="k">}</span> <span class="nt">--pretty</span><span class="o">=</span>format:<span class="s2">"%s"</span><span class="si">)</span>
<span class="c"># Is it marked as a feature commit?</span>
<span class="nv">FEATURE</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s2">"feat:"</span> <span class="o"><<<</span><span class="s2">"</span><span class="nv">$SUBJECT</span><span class="s2">"</span><span class="si">)</span>
<span class="c"># Is it marked as a bugfix commit?</span>
<span class="nv">FIX</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s2">"fix:"</span> <span class="o"><<<</span><span class="s2">"</span><span class="nv">$SUBJECT</span><span class="s2">"</span><span class="si">)</span>
<span class="c"># Is it marked as a chore commit?</span>
<span class="nv">CHORE</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s2">"chore:"</span> <span class="o"><<<</span><span class="s2">"</span><span class="nv">$SUBJECT</span><span class="s2">"</span><span class="si">)</span>
<span class="c"># Get the body of the commit</span>
<span class="nv">BODY</span><span class="o">=</span><span class="si">$(</span>git log <span class="nt">-1</span> <span class="k">${</span><span class="nv">COMMIT</span><span class="k">}</span> <span class="nt">--pretty</span><span class="o">=</span>format:<span class="s2">"%b"</span><span class="si">)</span>
<span class="c"># Does the body contain a link to a JIRA-number</span>
<span class="nv">JIRA_ID</span><span class="o">=</span><span class="si">$(</span><span class="nb">grep</span> <span class="nt">-Eo</span> <span class="s2">"JIRA-[[:digit:]]+"</span> <span class="o"><<<</span><span class="nv">$BODY</span><span class="si">)</span>
<span class="c"># Get last JIRA-number of the body (body might reference others)</span>
<span class="nv">JIRA_ID</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$JIRA_ID</span><span class="s2">"</span> | <span class="nb">tail</span> <span class="nt">-1</span><span class="si">)</span>
<span class="c"># Only include in list if commit contains a reference to a JIRA-number</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$JIRA_ID</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
if</span> <span class="o">[[</span> <span class="nv">$FEATURE</span> <span class="o">]]</span> <span class="o">&&</span> <span class="o">[[</span> <span class="nv">$INCLUDE_FEATURES</span> <span class="o">=</span> 1 <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">search_str</span><span class="o">=</span><span class="s2">"feat:"</span>
<span class="nv">subject</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">SUBJECT</span><span class="p">#*</span><span class="nv">$search_str</span><span class="k">}</span><span class="s2">"</span>
FEATURES+<span class="o">=(</span><span class="s2">"- [</span><span class="nv">$JIRA_ID</span><span class="s2">](</span><span class="nv">$REPOSITORY_URL</span><span class="s2">/</span><span class="nv">$JIRA_ID</span><span class="s2">):</span><span class="k">${</span><span class="nv">subject</span><span class="k">}</span><span class="s2">"</span><span class="o">)</span>
<span class="k">elif</span> <span class="o">[[</span> <span class="nv">$FIX</span> <span class="o">]]</span> <span class="o">&&</span> <span class="o">[[</span> <span class="nv">$INCLUDE_FIXES</span> <span class="o">=</span> 1 <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">search_str</span><span class="o">=</span><span class="s2">"fix:"</span>
<span class="nv">subject</span><span class="o">=</span><span class="k">${</span><span class="nv">SUBJECT</span><span class="p">#*</span><span class="nv">$search_str</span><span class="k">}</span>
FIXES+<span class="o">=(</span><span class="s2">"- [</span><span class="nv">$JIRA_ID</span><span class="s2">](</span><span class="nv">$REPOSITORY_URL</span><span class="s2">/</span><span class="nv">$JIRA_ID</span><span class="s2">):</span><span class="k">${</span><span class="nv">subject</span><span class="k">}</span><span class="s2">"</span><span class="o">)</span>
<span class="k">elif</span> <span class="o">[[</span> <span class="nv">$CHORE</span> <span class="o">]]</span> <span class="o">&&</span> <span class="o">[[</span> <span class="nv">$INCLUDE_CHORES</span> <span class="o">=</span> 1 <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">search_str</span><span class="o">=</span><span class="s2">"chore:"</span>
<span class="nv">subject</span><span class="o">=</span><span class="k">${</span><span class="nv">SUBJECT</span><span class="p">#*</span><span class="nv">$search_str</span><span class="k">}</span>
CHORES+<span class="o">=(</span><span class="s2">"- [</span><span class="nv">$JIRA_ID</span><span class="s2">](</span><span class="nv">$REPOSITORY_URL</span><span class="s2">/</span><span class="nv">$JIRA_ID</span><span class="s2">):</span><span class="k">${</span><span class="nv">subject</span><span class="k">}</span><span class="s2">"</span><span class="o">)</span>
<span class="k">fi
fi
done</span>
<span class="c"># Continue to next release if no commits are available since the previous release</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nt">-z</span> <span class="nv">$COMMITS</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
continue
fi
if</span> <span class="o">[[</span> <span class="nv">$LATEST_TAG</span> <span class="o">=</span> <span class="s2">"HEAD"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span>MARKDOWN+<span class="o">=</span><span class="s2">"## Unreleased</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="k">else
</span>MARKDOWN+<span class="o">=</span><span class="s2">"## Release </span><span class="nv">$LATEST_TAG</span><span class="s2"> (</span><span class="nv">$TAG_DATE</span><span class="s2">)</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="k">fi</span>
<span class="c"># List features</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$FEATURES</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">FEATURES</span><span class="o">=(</span><span class="si">$(</span><span class="k">for </span>l <span class="k">in</span> <span class="k">${</span><span class="nv">FEATURES</span><span class="p">[@]</span><span class="k">}</span><span class="p">;</span> <span class="k">do </span><span class="nb">echo</span> <span class="nv">$l</span><span class="p">;</span> <span class="k">done</span> | <span class="nb">sort</span> <span class="nt">-u</span><span class="si">)</span><span class="o">)</span>
MARKDOWN+<span class="o">=</span><span class="s2">"### ✨ Features</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="k">for </span>FEAT <span class="k">in</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FEATURES</span><span class="p">[@]</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span> <span class="k">do
</span>MARKDOWN+<span class="o">=</span><span class="s2">"</span><span class="nv">$FEAT</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">done
</span>MARKDOWN+<span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">fi</span>
<span class="c"># List bugfixes</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$FIXES</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">FIXES</span><span class="o">=(</span><span class="si">$(</span><span class="k">for </span>l <span class="k">in</span> <span class="k">${</span><span class="nv">FIXES</span><span class="p">[@]</span><span class="k">}</span><span class="p">;</span> <span class="k">do </span><span class="nb">echo</span> <span class="nv">$l</span><span class="p">;</span> <span class="k">done</span> | <span class="nb">sort</span> <span class="nt">-u</span><span class="si">)</span><span class="o">)</span>
MARKDOWN+<span class="o">=</span><span class="s2">"### 🐛 Bugfixes</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="k">for </span>FIX <span class="k">in</span> <span class="s2">"</span><span class="k">${</span><span class="nv">FIXES</span><span class="p">[@]</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span> <span class="k">do
</span>MARKDOWN+<span class="o">=</span><span class="s2">"</span><span class="nv">$FIX</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">done
</span>MARKDOWN+<span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">fi</span>
<span class="c"># List chores</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$CHORES</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">CHORES</span><span class="o">=(</span><span class="si">$(</span><span class="k">for </span>l <span class="k">in</span> <span class="k">${</span><span class="nv">CHORES</span><span class="p">[@]</span><span class="k">}</span><span class="p">;</span> <span class="k">do </span><span class="nb">echo</span> <span class="nv">$l</span><span class="p">;</span> <span class="k">done</span> | <span class="nb">sort</span> <span class="nt">-u</span><span class="si">)</span><span class="o">)</span>
MARKDOWN+<span class="o">=</span><span class="s2">"### 🧹 Chores</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="k">for </span>CHORE <span class="k">in</span> <span class="s2">"</span><span class="k">${</span><span class="nv">CHORES</span><span class="p">[@]</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span> <span class="k">do
</span>MARKDOWN+<span class="o">=</span><span class="s2">"</span><span class="nv">$CHORE</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">done
</span>MARKDOWN+<span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span>
<span class="k">fi</span>
<span class="c"># Append full changelog</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$LATEST_TAG</span> <span class="o">=</span> <span class="s2">"HEAD"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span>MARKDOWN+<span class="o">=</span><span class="s2">"📖 [Full changelog](</span><span class="k">${</span><span class="nv">AZURE_DEVOPS_GIT_URL</span><span class="k">}</span><span class="s2">/branchCompare?baseVersion=GT</span><span class="k">${</span><span class="nv">PREVIOUS_TAG</span><span class="k">}</span><span class="s2">&targetVersion=GBdevelop)</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="k">elif</span> <span class="o">[[</span> <span class="nt">-z</span> <span class="nv">$PREVIOUS_TAG</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
<span class="c"># First release, no way to compare</span>
<span class="nb">echo</span> <span class="s2">""</span>
<span class="k">else
</span>MARKDOWN+<span class="o">=</span><span class="s2">"📖 [Full changelog](</span><span class="k">${</span><span class="nv">AZURE_DEVOPS_GIT_URL</span><span class="k">}</span><span class="s2">/branchCompare?baseVersion=GT</span><span class="k">${</span><span class="nv">PREVIOUS_TAG</span><span class="k">}</span><span class="s2">&targetVersion=GT</span><span class="k">${</span><span class="nv">LATEST_TAG</span><span class="k">}</span><span class="s2">)</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="k">fi
done</span>
<span class="c"># Save our markdown to a file</span>
<span class="nb">printf</span> <span class="s2">"%b"</span> <span class="s2">"</span><span class="nv">$MARKDOWN</span><span class="s2">"</span> <span class="o">></span> CHANGELOG.md
</code></pre></div></div>Tim KlingeleersWhen you make use commit formats like conventional commits, this standardisation can get you some useful benefits. In this scenario, I wanted to create a changelog in markdown format, that listed all of the bugfixes and features that were created per release and link to a JIRA ticket that is associated with it. Let’s take a look how this was achieved.App wrapping a website with Xamarin2017-08-13T16:00:19+00:002017-08-13T16:00:19+00:00https://tim.klingeleers.be/2017/08/13/app-wrapping-website-xamarin<p>Clients often want their website available in the app store, mostly just for app store presence. I got asked to do app wrapping at work a while ago, because the client purchased a tool that did not have a native app available, only a mobile website. It just had to be made available in the internal app store. Colleagues had to be able to install it by themselves and use it on their own devices without too much fuzz.</p>
<p>In this post I want to show you some of the hurdles while developing a website wrapper and how to overcome them.</p>
<!--more-->
<h3 id="what-is-app-wrapping">What is app wrapping?</h3>
<p>It’s how I call packaging a website into an app. Wrapping a website into an app. Or just wrapping an app around a website. Hence, app wrapping. It’s actually just a form of hybrid app where you make a website available as an app.</p>
<h3 id="enterprise-environment">Enterprise environment</h3>
<p>When you are dealing with internal apps, you often have an internal app store available that is provided by an MDM (Mobile Device Management) solution. A few examples of these are Mobile Iron, AirWatch, Microsoft Intune and many more. In my case there is a mobile browser available, provided by the MDM solution as well, which sets up a secure tunnel to the intranet website that the client wanted to package as an app.</p>
<p>So you can already see that internal apps have to deal with different constraints than public apps.</p>
<p>There is only a requirement to support iOS in this case, so I’m using Xamarin.iOS for this one. You could easily extend the solution to Xamarin Forms by creating the appropriate renderers.</p>
<h3 id="show-the-website-full-screen">Show the website full screen</h3>
<p>First thing to do when app wrapping is show the website in a full screen browser. You don’t get a navigation bar like a normal browser in this case, so this poses a few requirements on your mobile website:</p>
<ul>
<li>Supply navigation on all pages</li>
<li>Show a back button at all times</li>
</ul>
<p>In the main Storyboard, you need to create a Web View (UIWebView) that spans the whole screen, so set the constraints accordingly. Then in the controller, use the ViewDidLoad method to load the website:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">override</span> <span class="k">async</span> <span class="k">void</span> <span class="nf">ViewDidLoad</span> <span class="p">()</span>
<span class="p">{</span>
<span class="k">base</span><span class="p">.</span><span class="nf">ViewDidLoad</span><span class="p">();</span>
<span class="c1">// Set to background color of website to load, so you don't get a white flash while loading the page</span>
<span class="n">WebView</span><span class="p">.</span><span class="n">BackgroundColor</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">UIColor</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0.635f</span><span class="p">,</span> <span class="m">0.925f</span><span class="p">,</span> <span class="m">1.0f</span><span class="p">);</span> <span class="c1">// equals #e3ebf3</span>
<span class="c1">// Prevent bounces so it feels more like an actual app</span>
<span class="n">WebView</span><span class="p">.</span><span class="n">ScrollView</span><span class="p">.</span><span class="n">Bounces</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
<span class="c1">// Load the actual page</span>
<span class="n">WebView</span><span class="p">.</span><span class="nf">LoadRequest</span> <span class="p">(</span><span class="k">new</span> <span class="nf">NSUrlRequest</span> <span class="p">(</span><span class="k">new</span> <span class="nf">NSUrl</span> <span class="p">(</span><span class="s">"https://example.com"</span><span class="p">)));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In this snippet, you can see I did some other settings as well. First is supplying a background color that matches the background of the website that is loaded. This is to prevent a white flash while loading the website. Secondly, I disable the bouncing of the default browser, so the website feels more like an actual app.</p>
<h3 id="opening-links">Opening links</h3>
<p>This is an internal website, so there are 2 different kind of links available:</p>
<ul>
<li>Intranet pages – these need to be handled by our MDM browser</li>
<li>Internet pages – these can be handled by the normal browser</li>
</ul>
<p>The UIWebView has a method ShouldStartLoad that can check which link is about to be opened, and allow you to handle the request yourself.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">ViewDidLoad</span> <span class="p">()</span>
<span class="p">{</span>
<span class="n">WebView</span><span class="p">.</span><span class="n">ShouldStartLoad</span> <span class="p">=</span> <span class="p">(</span><span class="n">webView</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">navigationType</span><span class="p">)</span> <span class="p">=></span>
<span class="p">{</span>
<span class="c1">// ...</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span> <span class="c1">// Notify the WebView that it can handle the request</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You can notify the UIWebView that you handled the request yourself, by returning false from this method. In that case, the UIWebView won’t handle the request anymore.</p>
<p>To open a different app on iOS, you can leverage <a href="https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html#//apple_ref/doc/uid/TP40007072-CH6-SW8">app schemes</a>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">ViewDidLoad</span> <span class="p">()</span>
<span class="p">{</span>
<span class="n">WebView</span><span class="p">.</span><span class="n">ShouldStartLoad</span> <span class="p">=</span> <span class="p">(</span><span class="n">webView</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">navigationType</span><span class="p">)</span> <span class="p">=></span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nf">OpenInMDMBrowser</span><span class="p">(</span><span class="n">request</span><span class="p">))</span>
<span class="p">{</span>
<span class="c1">// Naive implementation to change the URL scheme</span>
<span class="n">UIApplication</span><span class="p">.</span><span class="n">SharedApplication</span><span class="p">.</span><span class="nf">OpenUrl</span><span class="p">(</span>
<span class="k">new</span> <span class="nf">NSUrl</span><span class="p">(</span>
<span class="n">request</span><span class="p">.</span><span class="n">Url</span><span class="p">.</span><span class="n">AbsoluteString</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="s">"http://"</span><span class="p">,</span> <span class="s">"mdmbrowser://"</span><span class="p">).</span><span class="nf">Replace</span><span class="p">(</span><span class="s">"https://"</span><span class="p">,</span> <span class="s">"mdmbrowser://"</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">);</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span> <span class="c1">// Notify the WebView that we handled the action ourselves</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span> <span class="c1">// Notify the WebView that it can handle the request</span>
<span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In the snippet above, I did a naive implementation to change http:// and https:// to the required app scheme. The mdmbrowser:// scheme is different depending on the app you want to open. A different MDM provider, means a different scheme.</p>
<p>So if you want to open a URL in Safari, outside of your app, you can do the same thing but leave the http:// or https:// scheme.</p>
<h3 id="dealing-with-impossible-requests">Dealing with impossible requests</h3>
<p>It’s not all about opening links though. Sometimes theres an action that’s you want to prevent or leverage in your app. In my case I had to prevent users from changing their password through the app wrapper. For this, you can once again leverage the ShouldStartLoad method:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">WebView</span><span class="p">.</span><span class="n">ShouldStartLoad</span> <span class="p">=</span> <span class="p">(</span><span class="n">webView</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">navigationType</span><span class="p">)</span> <span class="p">=></span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nf">IsPasswordChange</span><span class="p">(</span><span class="n">request</span><span class="p">))</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">alertController</span> <span class="p">=</span> <span class="n">UIAlertController</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="s">"Change password"</span><span class="p">,</span>
<span class="s">"You can't change your password through this app."</span><span class="p">,</span> <span class="n">UIAlertControllerStyle</span><span class="p">.</span><span class="n">Alert</span><span class="p">);</span>
<span class="c1">// Add action</span>
<span class="n">alertController</span><span class="p">.</span><span class="nf">AddAction</span><span class="p">(</span><span class="n">UIAlertAction</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="s">"OK"</span><span class="p">,</span> <span class="n">UIAlertActionStyle</span><span class="p">.</span><span class="n">Default</span><span class="p">,</span> <span class="k">null</span><span class="p">));</span>
<span class="c1">// Present alert</span>
<span class="nf">PresentViewController</span><span class="p">(</span><span class="n">alertController</span><span class="p">,</span> <span class="k">true</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span> <span class="c1">// Notify the WebView that we handled the action ourselves</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>
<p>This example shows that you can actually do whatever you want, depending on the request that comes in. In my case, that’s just showing an alert to the user that the action is not possible. And in the end returning false so that the UIWebView won’t deal with the request.</p>
<h3 id="apple-app-store-rejection">Apple App Store rejection?</h3>
<p>If you try to submit these kinds of apps to the public App Store without a lot of added functionality, Apple will most likely reject it based on <a href="https://developer.apple.com/app-store/review/guidelines/#minimum-functionality">their Minimum Functionality rule</a> which states:</p>
<blockquote>
<p>Your app should include features, content, and UI that elevate it beyond a repackaged website. If your app is not particularly useful, unique, or “app-like,” it doesn’t belong on the App Store.</p>
<p>— App Store Review Guidelines, by Apple Developer</p>
</blockquote>
<p>But for internal purposes you don’t have to deal with Apple’s review process, so you have more opportunities and no risk for rejection there.</p>
<h3 id="closing-words">Closing words</h3>
<p>There are still some other things to keep in mind. On iOS, you can’t open http:// schemes in an app without <a href="https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33">configuring ATS</a>. If you have a file upload somewhere, make sure that you include the permissions to use the camera and/or photo library in your Info.plist. If you don’t, your app will crash.</p>
<p>Checking the reachability of the website is an important part as well. You should show the users an appropriate message when they don’t have an internet connection, the VPN tunnel isn’t available or the website they’re trying to open is down.</p>
<p>I also have a requirement to login into ADFS without the user noticing, because they are logged out automatically every day. That means I need to open a different ViewController where I can store the credentials (in a safe way!) initially, and make use of Javascript to automate the login afterwards. How you can achieve this will be for another post.</p>
<p>So it is certainly possible to do app wrapping with Xamarin, but I’m not sure if using Xamarin is actually the best possible approach. Which techniques do you use for app wrapping? Please leave a comment!</p>Tim KlingeleersClients often want their website available in the app store, mostly just for app store presence. I got asked to do app wrapping at work a while ago, because the client purchased a tool that did not have a native app available, only a mobile website. It just had to be made available in the internal app store. Colleagues had to be able to install it by themselves and use it on their own devices without too much fuzz. In this post I want to show you some of the hurdles while developing a website wrapper and how to overcome them.Android 64k method limit in Xamarin2017-05-08T10:00:54+00:002017-05-08T10:00:54+00:00https://tim.klingeleers.be/2017/05/08/android-64k-method-limit-xamarin<p>Last week, the nightly build of my Android project failed all of a sudden. It was apparently related to the 64k method limit than Android poses for DEX-files. I wasn’t aware how much impact the NuGet packages have on that method count. I want to show you my journey to resolving this issue.</p>
<!--more-->
<h3 id="tldr">TL;DR</h3>
<p>When you run into the 64k limit, you can use ProGuard and Multi-Dex to resolve the issue. Make sure to update ProGuard when you use Xamarin.Android 7.2 or lower and target API level 24+.</p>
<h3 id="64k-method-limit">64k method limit</h3>
<p>Android apps run on Dalvik or ART (Android Runtime), depending on the Android version you use. Dalvik has a few limitations, including the 64k method limit. In a DEX-file (which stands for Dalvik Executable), you can only reference the first 65,536 methods. If you exceed that limit you get the following build error in Xamarin:</p>
<blockquote>
<p>Tool exited with code: 2.<br />
/Library/Frameworks/Mono.framework/External/xbuild/Xamarin/Android/Xamarin.Android.Common.targets : error : trouble writing output: Too many field references: 74105; max is 65536.</p>
</blockquote>
<p>My app itself was only consuming 2500 methods of the total. So the rest was added through NuGet packages. The biggest method consumers were the Android support libraries (40503 methods), Google for Analytics (19930 methods) and Firebase for notifications (7258 methods).</p>
<!--more-->
<h3 id="proguard">ProGuard</h3>
<p>You use ProGuard to remove unused classes, fields and methods. So it can be used to work around the 64k limit. It essentially shrinks your app.</p>
<p>You can enable ProGuard at the project settings:</p>
<p><a href="/wp-content/uploads/2017/05/proguard.jpg"><img loading="lazy" class="alignnone wp-image-441 size-full" src="/wp-content/uploads/2017/05/proguard.jpg" alt="" width="1498" height="1114" /></a></p>
<p>There is a quirk though: if you enable it and build again, you are most likely to run into this exception:</p>
<blockquote>
<p>java.io.IOException: Can’t read [/Library/Frameworks/Xamarin.Android.framework/Versions/7.2.0-7/lib/xbuild-frameworks/MonoAndroid/v7.0/mono.android.jar] (Can’t process class [android/app/ActivityTracker.class] (Unsupported class version number [52.0] (maximum 51.0, Java 1.7)))</p>
</blockquote>
<h4 id="updating-proguard">Updating ProGuard</h4>
<p><strong>Update: as mentioned in the comments, updating ProGuard is no longer required since Xamarin.Android v7.3 was released as part of <a href="https://releases.xamarin.com/stable-release-15-2/">the Xamarin release 15.2</a>. It now <a href="https://developer.xamarin.com/releases/android/xamarin.android_7/xamarin.android_7.3/#New_Features">bundles its own up-to-date copy of ProGuard</a> (v5.3.2). Xamarin.Android v7.3 has been released as a stable on May 10th 2017.</strong></p>
<p>This is caused by Xamarin.Android v7.0 (see <a href="https://developer.xamarin.com/releases/android/xamarin.android_7/xamarin.android_7.0/">the release notes</a>), which requires JDK 1.8 if you target Android API 24+. So, the fix is to update ProGuard to the latest version on your build machine.</p>
<p>You can find ProGuard at the Android SDK location. You can find the SDK location in Xamarin Studio under Preferences > Projects > SDK Locations > Android. On my MacOS environment, the SDK is found here:</p>
<blockquote>
<p>/Users/<username>/Library/Developer/Xamarin/android-sdk-macosx</username></p>
</blockquote>
<p>At that location, in the <em>tools</em> directory you can find <em>proguard</em>. Simply rename the <em>proguard</em> directory and replace it with the contents of the latest version of <a href="https://sourceforge.net/projects/proguard/files/proguard/">ProGuard that you can find on Sourceforge</a>.</p>
<h3 id="multi-dex-to-the-rescue">Multi-Dex to the rescue</h3>
<p>In case ProGuard doesn’t get you far enough, you can enable Multi-Dex in the project settings. It splits up the DEX-files, so this prevents them from going over the 64k limit.</p>
<p>You can enable Multi-Dex in the project settings, at the same location where you found ProGuard:</p>
<p><a href="/wp-content/uploads/2017/05/multidex.jpg"><img loading="lazy" class="alignnone wp-image-440 size-full" src="/wp-content/uploads/2017/05/multidex.jpg" alt="" width="1498" height="1114" /></a></p>
<p>Keep in mind that you should first try to resolve the issue with ProGuard. Only enable Multi-Dex if you really need to. This is a warning that is also shown in the info icon in Xamarin Studio.</p>Tim KlingeleersLast week, the nightly build of my Android project failed all of a sudden. It was apparently related to the 64k method limit than Android poses for DEX-files. I wasn’t aware how much impact the NuGet packages have on that method count. I want to show you my journey to resolving this issue.A look under the hood of Xamarin Forms2017-05-05T14:59:30+00:002017-05-05T14:59:30+00:00https://tim.klingeleers.be/mobile%20app%20development/look-under-hood-xamarin-forms<p>Have you always wondered how Xamarin Forms does it’s “magic”? Knowing how things work under the hood is super valuable, especially when things go wrong. This enables you to detect the issue yourself, without having to rely on the knowledge of other developers. In this article a part of the magic of Xamarin Forms will be unraveled, as we take a look under the hood.</p>
<!--more-->
<h3 id="xamarinios-and-xamarinandroid">Xamarin.iOS and Xamarin.Android</h3>
<p>Before we take a look at how Xamarin Forms actually works, you first have to understand how Xamarin.iOS and Xamarin.Android works. Xamarin Forms depends on these implementations.</p>
<p>I’m ignoring the other platforms like Windows Phone and Mac, to keep this article succinct.</p>
<h4 id="xamarinios">Xamarin.iOS</h4>
<p>Xamarin.iOS makes use of Mono to compile C# code into ARM assembly language, that can be used by your iOS devices. The native libraries and the compiled executable combined, form the IPA-file that can be uploaded to the App Store. Apple does not allow JIT (Just In Time) compilation, so it requires Xamarin apps to make use of AOT (Ahead of Time) compilation. There is a part of the app that runs on the Mono runtime, and makes use of bindings that call into the native (Objective-C) code and frameworks.</p>
<p>If you want an in depth explanation, I suggest you read the <a href="https://developer.xamarin.com/guides/ios/under_the_hood/architecture/">iOS architecture</a> article on the Xamarin website.</p>
<h4 id="xamarinandroid">Xamarin.Android</h4>
<p>Xamarin.Android also makes use of Mono, but it does not require you to do AOT compilation. Just like with Xamarin.iOS, a part of the app runs on the Mono runtime and also makes use of Android bindings to call the Android Runtime or Dalvik VM (depending on the Android version). This ultimately results in the APK-file, which is used to install the app and to upload to the Play Store.</p>
<p>If you want an in depth explanation, I suggest you read the <a href="https://developer.xamarin.com/guides/android/under_the_hood/architecture/">Android architecture</a> article on the Xamarin website.</p>
<h4 id="bindings">Bindings</h4>
<p>These bindings in both platforms are the key to allowing C# code to use native libraries and frameworks. Xamarin supplies bindings whenever there is a new release of a platform. The Xamarin team starts working on these bindings as soon as beta versions of the SDK’s are released. So usually these bindings are available for developers before the SDK gets out of beta.</p>
<p>You can also create your own bindings for frameworks/jar-files, but I’ll leave that for another blog post.</p>
<h3 id="xamarin-forms">Xamarin Forms</h3>
<p>For Xamarin Forms to work, you need platform specific projects, and a PCL or shared project that contains Forms specific code. The platform specific projects are the entry point for your app, and these call into your PCL or shared project. iOS has the AppDelegate and Android has the MainActivity to do so.</p>
<p>Forms supplies you with a lot of abstractions in the Xamarin.Forms package. These abstractions are classes with the common denominator of properties for controls that are available on each platform. For example: a Xamarin Forms button has properties to set the Text, BackgroundColor, TextColor, Font, and many others. But there are some things you can’t control through the properties supplied in the abstraction. For example, a button in Android always capitalises the text that it contains by default, and you have no way to disable that directly with a property on the Xamarin Forms class.</p>
<h4 id="renderers">Renderers</h4>
<p>Xamarin Forms makes use of renderers that convert these abstractions into platform specific controls. These renderers build on the Xamarin.iOS and Xamarin.Android bindings that we talked about earlier. Take a look at all the available renderers for <a href="https://github.com/xamarin/Xamarin.Forms/tree/master/Xamarin.Forms.Platform.iOS/Renderers">iOS</a> and <a href="https://github.com/xamarin/Xamarin.Forms/tree/master/Xamarin.Forms.Platform.Android/Renderers">Android</a>. The <em>ActivityIndicatorRenderer</em> is probably the easiest implementation of a renderer, so I suggest you take a look at that one first to prevent being overwhelmed. The <em>ActivityIndicator</em> is implemented as a <em>UIKit.UIActivityIndicatorView</em> on iOS, and a _Android.Widget.ProgressBar _on Android.</p>
<p>iOS renderer for the <em>ActivityIndicator</em>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ActivityIndicatorRenderer</span> <span class="p">:</span> <span class="n">ViewRenderer</span><span class="p"><</span><span class="n">ActivityIndicator</span><span class="p">,</span> <span class="n">UIActivityIndicatorView</span><span class="p">></span>
<span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Android renderer for the <em>ActivityIndicator</em>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ActivityIndicatorRenderer</span> <span class="p">:</span> <span class="n">ViewRenderer</span><span class="p"><</span><span class="n">ActivityIndicator</span><span class="p">,</span> <span class="n">AProgressBar</span><span class="p">></span>
<span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If you take a look at these renderers, you can see they subclass the ViewRenderer class. The first generic argument is the abstraction supplied by Xamarin Forms, the second argument is the platform specific control. Such a ViewRenderer contains 2 important properties, being <em>Control</em> and <em>Element</em>. Control is the platform specific control, while Element gives you access to the Xamarin Forms abstraction properties.</p>
<p>These renderers are one of the cornerstones of how Xamarin Forms works, so some of them can be very complex to understand. To get a deeper understanding, I suggest you take a look at some of the provided renderers on Github.</p>
<h4 id="custom-renderers--effects">Custom renderers & effects</h4>
<p>When something is not available in Xamarin Forms, you can always create your own renderer. You can do this by subclassing an existing renderer, or make a completely new one by subclassing ViewRenderer. This means that everything that is possible with Xamarin.iOS or Xamarin.Android, is also possible in Xamarin Forms.</p>
<p><a href="https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/effects/introduction/">Effects</a> work almost the same as a renderer, but are often easier to understand and implement. So if an effect does the job, use that to your advantage.</p>
<h4 id="embedding-native-controls">Embedding native controls</h4>
<p>Since Xamarin Forms 2.2.0 and higher, you can <a href="https://blog.xamarin.com/embedding-native-controls-into-xamarin-forms/">embed native controls</a> without using a renderer. This is easiest with a shared project, because you can use compiler directives to get to the native controls. If you only want to embed a native control in XAML, you can also use it in a PCL project, but you can no longer use XAML compilation if you do so.</p>
<h3 id="the-magic-unraveled">The magic unraveled</h3>
<p>So now you know that Xamarin Forms builds on what Xamarin.iOS and Xamarin.Android already offer by using bindings and the mono framework and runtime. You’ve also learned that the cornerstone of Xamarin Forms are the renderers that are provided by Xamarin.</p>Tim KlingeleersHave you always wondered how Xamarin Forms does it’s “magic”? Knowing how things work under the hood is super valuable, especially when things go wrong. This enables you to detect the issue yourself, without having to rely on the knowledge of other developers. In this article a part of the magic of Xamarin Forms will be unraveled, as we take a look under the hood.Security in Xamarin: certificate pinning2017-04-21T14:30:11+00:002017-04-21T14:30:11+00:00https://tim.klingeleers.be/2017/04/21/security-xamarin-certificate-pinning<p>We all know security is important, but implementing security measures properly is often a difficult or obscure task. I’m trying to create awareness for this topic, for myself to gain a deeper understanding and for others to benefit from my findings along the way. And the best way to learn is by teaching, right? First up in this app security series is certificate pinning. Why would you need it and how would you implement it in a Xamarin Forms app?</p>
<!--more-->
<h3 id="a-little-bit-of-history">A little bit of history</h3>
<p>Just a quick note: SSL is the predecessor of TLS, but they are often used interchangeably. I’ll use TLS in this article from now on, although you can also read this as SSL if you want.</p>
<p>TLS for the web has become fairly familiar now. We check if there is a “Secure” or padlock icon in our address bar before entering credit card data or username and password. This padlock ensures us that we can trust the website we’re on. It looks something like this in Chrome:</p>
<p><img src="/wp-content/uploads/2017/04/ssl_padlock.jpg" alt="SSL padlock" /></p>
<blockquote>
<p>In fact to be really sure you would actually need to check the Certificate Authority (CA) that provided the certificate, but that’s way too complex for regular use cases and normal users. Remember <a href="https://en.wikipedia.org/wiki/DigiNotar">the history of the DigiNotar CA</a> and Google wildcard certificates? The padlock was still there and browsers wouldn’t show a warning, but it wasn’t using Google’s CA anymore.</p>
</blockquote>
<p>Within an app, a user does not have this padlock to check if the connection is secure. There is no address bar or other OS functionality that ensures them of a proper TLS connection. The review process won’t catch this, because developers can have valid reasons to use regular HTTP connections. Checking app reviews is also not sufficient, because wrong TLS handling can get introduced in every new version. Users ultimately have to put their <strong>trust in you</strong> (yes, you, the developer of the app) to implement this correctly.</p>
<p><a href="https://www.owasp.org/index.php/Mobile_Top_10_2016-M3-Insecure_Communication">Insecure communication</a> is on the OWASP Mobile Top 10 for a very good reason. The OWASP website provides tips on how to prevent this, but these are guidelines. They also provide some <a href="https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning">basic examples</a> and an extensive reasoning behind certificate pinning. Well worth the read if you want details!</p>
<h3 id="what-happens-if-i-do-securitywrong">What happens if I do security wrong?</h3>
<p>Let’s first set the scene… Say you are developing an app that uses a service on a staging environment. That staging environment uses a self signed certificate issued by your companies internal CA.</p>
<p>Your app will give a connection error by default in this case, since it doesn’t trust the CA that is used to create the self signed certificate. You have a few options here. The option I found most often on blogs and StackOverflow is probably the easiest: disable TLS checks altogether. Most of the time this suggestion lacks a warning that this is the least secure approach to take, and should <strong>never</strong> be implemented in production code.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ServicePointManager</span><span class="p">.</span><span class="n">ServerCertificateValidationCallback</span> <span class="p">+=</span>
<span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">certificate</span><span class="p">,</span> <span class="n">chain</span><span class="p">,</span> <span class="n">sslPolicyErrors</span><span class="p">)</span> <span class="p">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span> <span class="c1">// this effectively disables all certificate checks, never use this approach in production code!</span>
<span class="p">}</span>
</code></pre></div></div>
<p>So let’s say you did go for this approach and disabled TLS for your staging environment. Then there is a deadline coming up and some unexpected events happen just before that deadline. What could happen is that these kind of workarounds are forgotten about and stay in your code. Result: the workaround for your staging environment ends up in your production app and you now have an insecure app.</p>
<p>This is the time where an attacker can route your users through his own network/proxy (with Fiddler or <a href="https://en.wikipedia.org/wiki/ARP_spoofing">ARP spoofing</a> for example) and read and even manipulate all traffic that is sent to your API, even though it is sent over HTTPS. Your users won’t know this is happening, because they can’t see that your app is insecure. What happens is that this attacker can inject his own CA in the middle, and your app would just accept that. This is an example of a “man in the middle” attack. Be aware that the attacker can route all traffic through his computer, even if he does not own the router/network. This is where ARP spoofing is often used.</p>
<h3 id="lets-do-securitythe-right-way">Let’s do security the right way</h3>
<p>Always use valid certificates and don’t disable the TLS checks that are provided by default. Also don’t override Apple’s ATS (App Transport Security) policy unless strictly required, it’s enabled by default for a reason.</p>
<blockquote>
<p>In corporate environments you sometimes just have to deal with self signed certificates on non-production environments. In this case, if possible, you could opt to install/trust the CA on your device to work around the warning that the HttpClient gives you by default. Make sure your testers do the same thing.</p>
<p>If you can, just use a valid certificate, it will make your life a lot easier. These certificates can now even be acquired for free with services like <a href="https://letsencrypt.org/">Let’s Encrypt</a>. So there is absolutely no reason for not using certificates in production! Your users will thank you for your effort.</p>
</blockquote>
<p>Whether or not you should do certificate pinning boils down to a simple trust issue. How much trust do you put in your CA? What happens if the CA gets compromised? If you don’t have an issue with that, you could just rely on the normal certificate chain, and don’t pin to anything. OWASP tells you to always pin because “<a href="https://blog.cryptographyengineering.com/2012/02/28/how-to-fix-internet/">the internet is broken</a>”, which is a must-read article if you want more detail.</p>
<h3 id="certificate-pinning">Certificate pinning</h3>
<p>Certificate pinning allows you to make sure you are talking to the exact server you meant to talk to. If you are developing a banking app, or something that contains very sensitive data, you should never put your trust in CA’s. If you don’t do certificate pinning, someone can easily see his own traffic of the app through a proxy, as long as he installs the proxy’s CA certificate on the device. Technically the attacker could also manipulate the app code (by decompiling, editing and recompiling) to circumvent your certificate pinning solution, but it makes the attackers job a lot harder. In most cases it’s not really an issue if someone is able to see the traffic for his own device.</p>
<p>When checking certificates manually, you have a few options available. Safe bets are to check for the public key or the thumbprint of the certificate. You could also validate the full certificate chain, like the OWASP best practices mention.</p>
<p>In Xamarin Forms apps, you can use the <a href="https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback(v=vs.110).aspx">ServerCertificateValidationCallback</a> property on the ServicePointManager class to handle this globally, like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ServicePointManager</span><span class="p">.</span><span class="n">ServerCertificateValidationCallback</span> <span class="p">+=</span>
<span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">certificate</span><span class="p">,</span> <span class="n">chain</span><span class="p">,</span> <span class="n">sslPolicyErrors</span><span class="p">)</span> <span class="p">=></span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In other Xamarin apps that don’t use Forms, you are mostly better off by implementing the platform specific alternatives. These are not handled in this article.</p>
<h3 id="so-whichcertificate-do-you-pin-to">So which certificate do you pin to?</h3>
<p>You also have a few options here. Certificates are acquired through a Certificate Authority, so you get a chain of certificates you could potentially pin to. The flavours can be either certificate pinning or CA pinning. We’ll use the public key of the certificates in the following examples.</p>
<h4 id="the-leaf-certificate-certificate-pinning">The leaf certificate (certificate pinning)</h4>
<p>The leaf is the actual certificate you are using on your API and is usually valid for a relative short amount of time (from a couple of months to 1 or 2 years). For this website, this is the leaf certificate at the time of writing:</p>
<p><img src="/wp-content/uploads/2017/04/LeafCertificate.jpg" alt="Leaf certificate" /></p>
<p>Note that this certificate isn’t valid for a long period of time. Let’s Encrypt certificates are usually valid for a period of 90 days. Other CA’s have different, mostly longer, validity periods.</p>
<p>If you pin to this certificate, you have to make sure to update your app regularly so it validates new certificates. This means you also need to make sure your users update their app often or force them to update. Otherwise they will not be able to communicate with your API anymore, which would probably break your app. You can also set up some sort of grace period, where multiple public keys can be used simultaneously. You then have some overlap in validity periods while the certificates are renewed.</p>
<blockquote>
<p>Never force an update on your users unless it’s absolutely necessary! If you discover a severe security issue, this is a valid reason to force an update in my opinion.</p>
</blockquote>
<p>So how do you pin to the leaf certificate? This example shows pinning to the public key:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// validkeys should be a list of strings containing the trusted public keys</span>
<span class="n">ServicePointManager</span><span class="p">.</span><span class="n">ServerCertificateValidationCallback</span> <span class="p">+=</span>
<span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">certificate</span><span class="p">,</span> <span class="n">chain</span><span class="p">,</span> <span class="n">sslPolicyErrors</span><span class="p">)</span> <span class="p">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="n">validkeys</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">certificate</span><span class="p">?.</span><span class="nf">GetPublicKeyString</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You could also use the thumbprint instead of the public key, both are equally safe.</p>
<h4 id="the-intermediate-certificate-ca-pinning">The intermediate certificate (CA pinning)</h4>
<p>The CA or Intermediate certificate is usually valid for a lot longer period. For this website, it’s valid until nearly 4 years in the future.</p>
<p><img src="/wp-content/uploads/2017/04/IntermediateCertificate.jpg" alt="Intermediate certificate" /></p>
<p>This means you don’t have to update your app as often, or perhaps never at all to update certificate checks. However this isn’t as secure as pinning to the leaf certificate, since all certificates that are issued by the CA are trusted. OWASP does not recommend this approach, since you have now put your trust in the CA again. So in fact this doesn’t help you a lot. It would only prevent an attacker from intercepting traffic, even if he installs his own proxy CA on the device.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ServicePointManager</span><span class="p">.</span><span class="n">ServerCertificateValidationCallback</span> <span class="p">+=</span>
<span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">certificate</span><span class="p">,</span> <span class="n">chain</span><span class="p">,</span> <span class="n">sslPolicyErrors</span><span class="p">)</span> <span class="p">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">certificate</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">cert</span> <span class="k">in</span> <span class="n">chain</span><span class="p">.</span><span class="n">ChainPolicy</span><span class="p">.</span><span class="n">ExtraStore</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">cert</span><span class="p">.</span><span class="n">Subject</span> <span class="p">==</span> <span class="n">certificate</span><span class="p">?.</span><span class="n">Issuer</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">validkeys</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">cert</span><span class="p">.</span><span class="nf">GetPublicKeyString</span><span class="p">());</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In this example I check if the issuer name of the certificate matches the subject name of one of the certificates in the certificate chain (which seems to be in the ExtraStore). There are plenty of other ways you could implement this, so adjust this example to your needs.</p>
<h4 id="the-root-certificate-ca-pinning">The root certificate (CA pinning)</h4>
<p>This gives you almost the same pro’s and con’s as pinning to the intermediate certificate. The validity period is usually longer than the intermediate certificate. In this case it’s only a few months, but it could also be a few years depending on your CA.</p>
<p><img src="/wp-content/uploads/2017/04/RootCertificate.jpg" alt="Root certificate" /></p>
<h3 id="conclusion">Conclusion</h3>
<p>Always use valid certificates for your API’s, no matter what. Using certificates is free since Let’s Encrypt was introduced!</p>
<p>Certificate pinning is mostly solving a trust issue. How much trust do you put in the CA’s? If you want to do certificate pinning, you have to make a decision between update intervals. If you release your app often, and security is of the utmost importance, then go for leaf certificate pinning. Otherwise, if you just want an extra layer of (moderate) security, go for intermediate certificate pinning. This prevents you from the hassle of frequently updating the public keys or thumbprints, but puts your trust in CA’s once again. Remember, it’s all about trust!</p>
<p>If you happen to know a better way of checking certificates or how to handle certificate renewals, please let me know in the comments below.</p>Tim KlingeleersWe all know security is important, but implementing security measures properly is often a difficult or obscure task. I’m trying to create awareness for this topic, for myself to gain a deeper understanding and for others to benefit from my findings along the way. And the best way to learn is by teaching, right? First up in this app security series is certificate pinning. Why would you need it and how would you implement it in a Xamarin Forms app?NativeScript vs Xamarin: how to make a choice2017-02-12T20:00:25+00:002017-02-12T20:00:25+00:00https://tim.klingeleers.be/2017/02/12/nativescript-vs-xamarin-make-choice<p style="text-align: left;">
Can’t choose between all the mobile application platforms that are available today? Let’s find out if you can make a decision for your personal project or for your team, by comparing two: NativeScript vs Xamarin.
</p>
<p style="text-align: left;">
How do you even start making a decision without in depth knowledge of each platform? Both platforms have big companies behind them. Xamarin is backed by Microsoft, where NativeScript is backed by Telerik. In this blogpost I’ll try to give you some insight in each of the technologies and when you should choose one or the other.
</p>
<!--more-->
<h3 id="my-background">My background</h3>
<p>I am obliged to say that I am a certified Xamarin developer. But I’m always keeping an eye out for other technologies. So even though I might look biased, I try to make a fair comparison between the 2 platforms. I have been looking into NativeScript as a replacement for Xamarin because I was unhappy with the development flow of Xamarin. I’ll elaborate on that flow later in this blogpost. During the investigation I tried to rebuild an app I was working on. This way I could find out how NativeScript would compare to Xamarin in a real world situation. Let’s get started on the NativeScript vs Xamarin comparison.</p>
<p>By the way, whenever I am referring to Angular, I mean Angular 2 and upwards.</p>
<h3 id="flavours">Flavours</h3>
<h4 id="xamarin-native-and-xamarin-forms">Xamarin ‘native’ and Xamarin Forms</h4>
<p style="text-align: left;">
There are two flavours to build your apps in Xamarin. Xamarin ‘Native’ as I like to call it, allows you to develop UI’s independently for Android, iOS and/or UWP. This gives you a fair amount of code sharing capabilities, except for the UI. The benefit is that you can have widely varying UI’s on each platform.
</p>
<p style="text-align: left;">
Xamarin Forms on the other hand gives you the option to share a lot of your UI code as well. This is especially useful when the UI’s on each platform can look similar. For an elaborate discussion on these 2 flavours, you can read my other blogpost on <a href="https://timklingeleers-blog.azurewebsites.net/2016/01/22/xamarin-native-vs-xamarin-forms/" target="_blank" rel="noopener noreferrer">Xamarin Native vs Xamarin Forms</a>.
</p>
<h4 id="nativescript-and-nativescript--angular">NativeScript and NativeScript + Angular</h4>
<p>NativeScript has two flavours as well. First off there is regular NativeScript where you use an XML-style UI layer and Javascript code. On the other hand you can use NativeScript in combination with Angular. You use the same XML-style UI layer sprinkled with some Angular goodies. It is advisable to make use of TypeScript in this case, but you could opt for Javascript as well. Some people want to name this <a href="https://medium.com/@jeffwhelpley/angular-native-77e82687c579#.izy3s01so">Angular Native</a>, to become a bit more competitive in regards of naming with React Native, and just because it’s a mouthful.</p>
<p>In this NativeScript + Angular approach you can reuse most of the code you may have already written for your web-app and just build a new UI on top of that. You get to reuse your already existing services, models and more. This approach is a little harder than regular NativeScript development for newcomers, since it’s yet another layer of abstraction. Personally I found it helpful to first get a grasp on regular NativeScript. Learning what the Angular part adds afterwards gave some great insights.</p>
<h3 id="how-does-it-work">How does it work?</h3>
<h4 id="xamarin">Xamarin</h4>
<p>For Xamarin you use C# to implement your mobile apps. What happens with this C# code depends on the platform you are building for. On iOS this is compiled to ARM assembly language. On Android the same code is compiled to IL and packaged with MonoVM + JIT’ing. The Linker strips out unused code to keep your assemblies as small as possible when you release your app.</p>
<p>Since Xamarin does compile to assemblies, this requires recompilation of your app when you change code. This process can take some time and requires a restart of your app to see changes.</p>
<h4 id="nativescript">NativeScript</h4>
<p>NativeScript uses the Apple JavascriptCore Virtual Machine on iOS and the Google V8 JS Virtual Machine on Android. It uses the NativeScript Runtime to call the required VM methods in order to call native C++ methods on each platform. TJ VanToll gives a perfect explanation and insight in this process in <a href="http://developer.telerik.com/featured/nativescript-works/">his great blogpost</a>. Knowing how the platform works internally is important if you want to know why certain things are happening.</p>
<p>React Native is the biggest competitor to NativeScript in Javascript land. React Native has <a href="https://facebook.github.io/react/blog/2015/03/26/introducing-react-native.html">its own view on things</a>. A comparison with React Native would take us too far for now.</p>
<h3 id="pros-and-cons-for-xamarin">Pro’s and con’s for Xamarin</h3>
<p>Let’s see some of the good and bad points for Xamarin. This list is not limitative and some points are based on my personal opinion (e.g. not backed up with references).</p>
<h4 id="xamarin--whatsgood">Xamarin – what’s good?</h4>
<h5 id="solid-tooling"><strong>Solid tooling</strong></h5>
<p>Microsoft is, in my opinion, known for very good development tooling. Microsoft only acquired Xamarin <a href="https://blogs.microsoft.com/blog/2016/02/24/microsoft-to-acquire-xamarin-and-empower-more-developers-to-build-apps-on-any-device/#sm.00001mnpcwc1mudfox6qqh0u1h4zq">nearly a year ago on February 24th</a>, so not everything is integrated perfectly yet. Xamarin Studio and Visual Studio are getting more and more aligned. Forms Previewer and other helpful tools have been introduced since and I guess there is a lot more coming.</p>
<h5 id="open-source"><strong>Open source</strong></h5>
<p>Since the acquisition by Microsoft, most of the Xamarin codebase has become <a href="https://github.com/xamarin">open source</a>. This opens up a whole slew of possibilities when you run into a problem. It allows you to fix the issue yourself or at least figure out why something is happening.</p>
<h5 id="forms-previewer"><strong>Forms Previewer</strong></h5>
<p>While this is a good thing, <a href="https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-previewer/">it’s not perfect yet</a> and will not work in all situations. It makes sense this tool still has a ‘Preview’ label. The Forms Previewer does however try to solve a big part of the recompilation hassle and I have big expectations for the future. Having to recompile an entire app for a simple UI change is just annoying.<br />
<a href="http://gorillaplayer.com/">Gorilla Player</a> is an alternative that has been around a little bit longer but also has its own problems (for example: <a href="https://github.com/UXDivers/Gorilla-Player-Support/issues/136">you can’t use StaticResource for styling</a> and have to fallback on DynamicResource just for this tool).</p>
<h5 id="lots-of-plugins-available"><strong>Lots of plugins available</strong></h5>
<p>There are a lot of plugins available on NuGet and you can reuse normal .NET libraries as well. The reason for this is that Xamarin has been around for several years by now and the community is quite big. The most popular plugins are listed in <a href="https://github.com/xamarin/XamarinComponents">this repository on GitHub</a>. Giving a count is quite hard since there is not a single repository. This can make it hard to discover all available plugins.</p>
<h5 id="xamarin-test-cloud"><strong>Xamarin Test Cloud</strong></h5>
<p>Having an option to UI-test your app on a very broad range of devices can give you peace of mind. <a href="https://www.xamarin.com/test-cloud">Xamarin Test Cloud</a> allows you to test your app on over 2000 real devices. Integration with your UI code works seamlessly. Pricing can be high for indie developers, but for companies it’s a justified cost in my opinion.</p>
<h5 id="xamarin-university"><strong>Xamarin University</strong></h5>
<p>Read my post on “<a href="https://timklingeleers-blog.azurewebsites.net/2016/06/09/xamarin-university-worth-it/">Xamarin University: worth it?</a>” to find out more. Getting help from experienced trainers is invaluable.</p>
<h4 id="xamarin--whats-not-so-good">Xamarin – what’s not so good?</h4>
<h5 id="code-recompilation"><strong>Code recompilation</strong></h5>
<p>Whenever you change code, you have to wait for a recompile and restart of your app. This can take a few seconds and gets cumbersome fast. On the simulators/emulators it’s not that bad, but on a real device this cycle seems to take a lot longer. This is the biggest annoyance I have with Xamarin and the very reason I started looking into NativeScript.</p>
<h5 id="swiftobjective-c-compatibility"><strong>Swift/Objective-C compatibility</strong></h5>
<p>If you have to integrate iOS code that is originally written in Swift you might have a problem. Building C# bridges for these kind of libraries is a lot harder than it should be in my opinion. First you have to create Objective-C bridging headers, and from there you can use Objective-Sharpie to create a C# bridge. Even then you sometimes still run into <a href="https://forums.xamarin.com/discussion/73395/xamarin-does-not-support-binding-ios-swift-framework-to-csharp">problems</a>, making Swift libraries practically unusable. You have to be very proficient in native iOS development to know exactly what you have to do here. The Java part seems to be a lot easier to bridge to C#.</p>
<h5 id="styling"><strong>Styling</strong></h5>
<p>You can create resource dictionaries with all your styling. But you can only create implicit styles or make them explicit by <a href="https://developer.xamarin.com/guides/xamarin-forms/user-interface/styles/explicit/">adding a StaticResource or DynamicResource to the Style attribute of your UI element</a>. You can’t add multiple resources to the Style attribute without creating another explicit style like you can with CSS styling. A nice new option is that you can <a href="http://jmillerdev.net/creating-a-xamarin-forms-theme-assembly/">create reusable themes</a> with the new <code class="language-plaintext highlighter-rouge">MergedWith</code> feature of Xamarin. But this doesn’t seem to work flawlessly with the previewer though.</p>
<h3 id="pros-and-cons-fornativescript">Pro’s and con’s for NativeScript</h3>
<p>Let’s look at the list of good and bad points for NativeScript. Once again the list is not limitative.</p>
<h4 id="nativescript-whats-good">NativeScript – what’s good?</h4>
<h5 id="instant-recompile"><strong>Instant recompile</strong></h5>
<p>No recompilation is necessary because NativeScript uses the Javascript VM’s available on each platform. The <code class="language-plaintext highlighter-rouge">tns livesync --watch</code> command makes sure changes are pushed as a new JS bundle to the device. It then automatically refreshes itself in nearly no time. This is especially useful for fast UI development.</p>
<h5 id="easy-to-use-native-codelibraries"><strong>Easy to use native code/libraries</strong></h5>
<p>Using <a href="https://cocoapods.org/">CocoaPods</a> or Java JARs is fairly easy, since you can just call them in Javascript/Typescript without the need for bridging code. You need to know how to translate Objective-C/Swift and Java to Typescript though. You can transform this into a plugin for reuse by others as well. In any case it’s certainly easier than creating bindings in Xamarin.</p>
<h5 id="use-of-css"><strong>Use of CSS</strong></h5>
<p>Or SASS for that matter. You can base your app based on a default theme, and use classes on your UI elements just like you would with web development. This makes styling a lot more comprehensible than in Xamarin where you can only use one style “class” on an element.</p>
<h5 id="open-source-1"><strong>Open source</strong></h5>
<p>NativeScript has been open source since the start <a href="https://github.com/NativeScript/NativeScript">on GitHub</a>. So this is something where both Xamarin and NativeScript score points.</p>
<h4 id="nativescript--whats-not-so-good">NativeScript – what’s not so good?</h4>
<h5 id="platform-age"><strong>Platform age</strong></h5>
<p>NativeScript has only been around since 29 April 2015, when <a href="https://github.com/NativeScript/NativeScript/releases/tag/v1.0.0">version 1.0.0</a> saw the light. A year later <a href="https://github.com/NativeScript/NativeScript/releases/tag/v2.0.0">version 2.0.0</a> was released. So it is still fairly new. Since Angular came out of beta, the community around NativeScript started growing, but it still has to prove if it will survive in the future. Too much fragmentation would be bad for adoption. There are even ideas popping up to get <a href="https://nativescript.ideas.aha.io/ideas/NS-I-94">Vue.js support</a> in NativeScript, but I have no idea how viable that would be.</p>
<h5 id="not-a-lot-of-plugins-yet"><strong>Not a lot of plugins yet</strong></h5>
<p>Since NativeScript is fairly new, the plugin count is fairly low with <a href="http://nativescript.rocks/all.php">375 listed</a> on NativeScript.rocks at the time of writing. This number includes seeds and other things you can’t really count as a plugin per se. It’s only a matter of time to see this number of plugins increasing though. Now that Angular adoption is rising, things might change quickly in this area.</p>
<h5 id="no-easy-fallback-to-native-ui"><strong>No easy fallback to native UI</strong></h5>
<p>At this moment, there is <a href="https://github.com/NativeScript/ios-runtime/issues/219">no possibility to use Storyboards or XIB files</a> on iOS. Sometimes it’s just easier to use Storyboards, but this may be a personal preference as well. Although I haven’t really looked into <a href="http://developer.telerik.com/featured/apple-watch-and-the-cross-platform-crisis/">wearable development</a> with NativeScript, it seems to be possible, but I don’t know which restrictions there are here.</p>
<h5 id="testing"><strong>Testing</strong></h5>
<p>Telerik is working together with <a href="https://cloud.testdroid.com/">TestDroid</a> to offer a comparable alternative to Xamarin Test Cloud. This service only includes about 400 devices, which is a lot less than Xamarin has to offer. Also the prices seem to be higher. However, if you end up choosing NativeScript you should certainly invest in this for automated UI testing.</p>
<h3 id="how-to-decide">How to decide?</h3>
<table>
<thead>
<tr>
<th><img src="/wp-content/uploads/2017/02/xamarin.png" alt="Xamarin" /> Xamarin</th>
<th><img src="/wp-content/uploads/2017/02/nativescript.png" alt="NativeScript" /> NativeScript</th>
</tr>
</thead>
<tbody>
<tr>
<td>You are mainly invested in C#</td>
<td>You are mainly invested in Javascript or Typescript</td>
</tr>
<tr>
<td>You want to use Storyboards for iOS</td>
<td>Your focus is on web development</td>
</tr>
<tr>
<td>Necessary libraries are available for Xamarin (as a NuGet package)</td>
<td>You want to share Angular parts of a related website</td>
</tr>
<tr>
<td>IDE and more visual development tooling is important</td>
<td>You want to use Cocoapods or Swift libraries easily</td>
</tr>
<tr>
<td>You want to automatically test on a very broad range of devices</td>
<td>Fast UI development cycle is important</td>
</tr>
<tr>
<td>Community size is important <sup>*</sup></td>
<td> </td>
</tr>
<tr>
<td>Need to hire knowledgable consultants <sup>*</sup></td>
<td> </td>
</tr>
</tbody>
</table>
<p><sub>* This is mainly because of platform age</sub></p>
<p>Whichever platform you choose, it is always wise to have at least one person on your team that is proficient in native platform development for iOS and/or Android. That way you have the ability to incorporate native libraries more easily when they aren’t available as a plugin yet.</p>
<p>If you’re working in a team, using a statically typed language like C# or Typescript (or JS with <a href="https://flowtype.org/">Flow</a>) is advisable.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Comparing NativeScript vs Xamarin, there is no clear winner that you should always use. Making a choice mainly depends on the skills that are available in your team and the requirements of the app you are building. Keep in mind that there are other options available that might even be more appropriate in your specific case. Except for Xamarin and NativeScript for native app development, you should always consider React Native or real native development as well.</p>
<p>I hope this, rather long, blogpost gave you the necessary insight on how both platforms work, so you can make the right choice for your project.</p>
<p>If you think I made some wrong assumptions or you have a different opinion on something, please leave a comment below.</p>Tim KlingeleersCan’t choose between all the mobile application platforms that are available today? Let’s find out if you can make a decision for your personal project or for your team, by comparing two: NativeScript vs Xamarin. How do you even start making a decision without in depth knowledge of each platform? Both platforms have big companies behind them. Xamarin is backed by Microsoft, where NativeScript is backed by Telerik. In this blogpost I’ll try to give you some insight in each of the technologies and when you should choose one or the other.Yarn: the improved Node Package Manager2016-11-08T07:00:31+00:002016-11-08T07:00:31+00:00https://tim.klingeleers.be/2016/11/08/yarn-improved-node-package-manager<p>I was surprised when Facebook introduced Yarn on October 11. I didn’t expect anything to be wrong with Node Package Manager (NPM) itself, apart from the well-known <a href="http://www.theregister.co.uk/2016/03/23/npm_left_pad_chaos/">left-pad issue</a>. But when I started reading <a href="https://yarnpkg.com/">the introduction page</a> and <a href="https://code.facebook.com/posts/1840075619545360">the first blog by Facebook about it</a>, it became clear which issues they try to address.</p>
<!--more-->
<h3 id="what-yarn-tries-to-do-better">What Yarn tries to do better</h3>
<h4 id="caching-packages-locally">Caching packages locally</h4>
<p>It creates a local cache of all the packages that you ever installed. Because of that local cache, installing and restoring packages becomes a lot faster. This also enables you to work offline if needed.</p>
<p>A developer can also decide to include these packages as tarballs into the source repository. This way your build server has no direct dependency on the NPM registry. You can do that by adding a setting to the <a href="https://docs.npmjs.com/files/npmrc"><code class="language-plaintext highlighter-rouge">.npmrc</code> file</a>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn-offline-mirror=./any-directory
</code></pre></div></div>
<h4 id="lockfile-for-reliability">Lockfile for reliability</h4>
<p>It also adds a <code class="language-plaintext highlighter-rouge">yarn.lock</code> file to your repository. This includes all the packages including their version, tarball name and file hash. Because of that file, Yarn ensures that an install that worked on one device, also works on another device. Make sure to commit this file to your source control repository.</p>
<p>This is also possible with NPM by using <a href="https://docs.npmjs.com/cli/shrinkwrap"><code class="language-plaintext highlighter-rouge">npm shrinkwrap</code></a>, but it is a lesser known feature to a lot of developers. Yarn does that automatically for you.</p>
<h4 id="parallel-downloads">Parallel downloads</h4>
<p>NPM does all of the work per package and sequentially. Yarn on the other hand downloads as many packages as it can in parallel, thereby increasing installation times. I haven’t done exact benchmarks yet, but it ranges from about 1.2x to up to 10x faster installations. Yarn is consistently faster than NPM.</p>
<h3 id="switching-to-yarn-is-easy">Switching to Yarn is easy</h3>
<p>Since Yarn is built on top of NPM, you can still use the NPM commands and configuration you already know. But if you want to harness the real power of it there are a few commands you should be aware of:</p>
<p>Installing all packages in the <code class="language-plaintext highlighter-rouge">package.json</code> file:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install
//becomes
yarn
</code></pre></div></div>
<p>Installing a new package and including it as a dependency to the <code class="language-plaintext highlighter-rouge">package.json</code> file:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install packagename --save
//becomes
yarn add packagename
</code></pre></div></div>
<p>As you can see there is no need to explicitly save your package to the <code class="language-plaintext highlighter-rouge">package.json</code> file with Yarn. This prevents you from having local installs of packages, that are not available when another developer or the build server picks up your repository, causing the build to break.</p>
<h3 id="is-yarn-here-to-stay">Is yarn here to stay?</h3>
<p>Well, this is a rather hard question to answer. We’ve all seen what happened with the Node.js and io.js fork. In the end Node.js was improved because of the changes that io.js made in their fork. NPM might go down the same path and learn from Facebook’s implementation. They might resolve some (or all) of the shortcomings that Facebook addresses, therefore making Yarn obsolete again. But I guess that won’t happen anytime soon.</p>
<p>Since Yarn is very easy to pick up, a lot of developers are able to give Yarn a try in a project in less than 5 minutes. You’ll be amazed of the differences in installation speed and clean output.</p>
<p>There is also a big difference when doing CI builds with Yarn or NPM. In some cases having faster builds results in lower costs. I will add a post soon that makes it clear how you can use Yarn in Visual Studio Team Services builds. In short it comes down to installing Yarn from NPM, and after that executing the yarn command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm i yarn && yarn
</code></pre></div></div>Tim KlingeleersI was surprised when Facebook introduced Yarn on October 11. I didn’t expect anything to be wrong with Node Package Manager (NPM) itself, apart from the well-known left-pad issue. But when I started reading the introduction page and the first blog by Facebook about it, it became clear which issues they try to address.Xamarin University: worth it?2016-06-09T12:10:00+00:002016-06-09T12:10:00+00:00https://tim.klingeleers.be/2016/06/09/xamarin-university-worth-it<p>I’ve been using Xamarin University since april this year. My primary goal was to use it for certification purposes. The <a href="https://university.xamarin.com/resources/certification">certification process</a> requires you to follow several live classes where instructors go through the material using GoToMeeting. You can skip some of the required classes by taking an assessment exam.</p>
<h3 id="assessment-exam">Assessment exam</h3>
<p>When you have some experience with Xamarin, you can consider skipping some 100-level classes by taking an assessment exam. I went through all the required video’s for the assessment at a playback speed of 2x to glance through the material quickly. This gave me a solid idea about what level of knowledge would be required to pass the assessment exam.</p>
<!--more-->
<p>I managed to score a whopping 88% at the Xamarin University Assessment exam without too much effort. After the assessment I felt that one of the questions was just wrong. So I decided to email Xamarin University about it. Within no time they acknowledged the fact and corrected the question. It was an “all of the above” question, where you could check all answers as well, so that was a bit confusing.</p>
<p>So in fact my final score should have been 90%, but it doesn’t really matter. The minimum requirement was 80% over 50 questions.</p>
<h3 id="the-classes">The classes</h3>
<p>I needed to finish all of the required classes before I could take the final exam. Xamarin requires you to live attend most of the classes. If you attend all these classes, you get a link to take the exam.</p>
<p>At first I was a bit gutted by the fact that you had to attend live. I was so accustomed to learning on-demand with services like <a href="https://www.pluralsight.com/">Pluralsight</a> for example, that I was unsure of the added value of live classes. But after my first few classes, I was proven wrong. The instructors added a lot of value, especially when you had some questions regarding the class material. The other students’ questions, and sometimes even answers, were very valuable as well.</p>
<p>It took quite some effort to plan and take all the classes though, since the total runtime of all required classes were about 24 hours of live training (after skipping the assessment classes). This is especially hard because not every class is given every day. Sometimes you have to plan a few weeks in advance. I managed to plan a marathon during a week of vacation to get through it without too much hassle.</p>
<p>There are several class tracks, ranging from normal cross platform development to Xamarin Android and Xamarin iOS to Xamarin Forms. Windows Phone development is not required, but maybe this will change in the future since Microsoft is involved with Xamarin nowadays.</p>
<p>Kudos to the instructors (Judy McNeil, <a href="https://twitter.com/chrisvwyk">Chris van Wyk</a> and <a href="https://twitter.com/jdeboever">Jason DeBoever</a>) that I had during this time. Most of the time they managed to get a good mix between serious learning and some jokes. Jason had the odd habit of trying to check off every continent with attendants to his classes, which was quite amusing at times.</p>
<h3 id="studying-time">Studying time</h3>
<p>Finally I got through every required class and got a link to the final exam, so now the real studying could begin. I didn’t feel like going through every single class video again (there are videos of every class as well for reference), so I downloaded all presentation slides and went through every single one of them. There were about 1350 slides in total, but they contain nearly all information you would need for the exam.</p>
<p>You could choose to do the lab exercises from the classes again, but if you work with Xamarin on a regular basis this shouldn’t be needed. At least, I didn’t do them for my exam.</p>
<h3 id="the-final-exam">The final exam</h3>
<p>Before taking the exam I looked at the list of required classes once more and noticed that one particular class (XAM-370) disappeared from the list. It got replaced by another class in the time between studying for the exam and taking the exam. During the exam, no questions were asked about this particular class. So be prepared for changing requirements, but you should always be if you’re a developer :-).</p>
<p>The final exam requires you to get a score of 80% or higher with 150 questions. You get about 3 hours to complete it. I managed to complete the exam in about 2 hours and got a score of <strong>92%</strong>, which means I got 12 questions out of 150 wrong.</p>
<p><img src="/wp-content/uploads/2016/06/XamarinCert.png" alt="Xamarin certificate" /></p>
<p>Taking your time and logical thinking gets you quite far in the exam. If I can give you one tip it would be: if you don’t know the answer to a question, just go with your gut feeling and note the question number somewhere so you can get back to it when you have time left in the end. Not answering is guaranteed to be wrong.</p>
<p>Once you pass the exam you get a certificate and certification badges for use wherever you want. People can look you up as being certified through the <a href="https://university.xamarin.com/certification">Xamarin Developer Certification page</a>. And you also get a Xamarin Certification trophy to show off. I expected it to be plastic, but it turned out to be made of glass. Very nice!</p>
<p><img src="/wp-content/uploads/2016/06/MG_3791.png" alt="Xamarin Certified Mobile Developer trophy for Tim Klingeleers" /></p>
<h3 id="is-xamarin-university-worth-it">Is Xamarin University worth it?</h3>
<p>There is a steep price point of $ 1995 for enrollment in Xamarin University for your first year. It drops to $ 1499 for each subsequent year. However, if you think about the instructors who put a lot of time and effort in this, it isn’t such a high price.</p>
<p>Personally I certainly believe it is worth it, at least for your initial certification process. Although I was using Xamarin for quite some time already I have learned new things in every class I took, even in the 101 classes! So even if you don’t want to get certified, you certainly get a lot of value out of Xamarin University.</p>
<p>You also get Office Hours, which means you get up to 8 sessions of about 30 minutes. With Office Hours you can get answers from instructors about classes, code reviews, architectural guidance or general mobile strategy. I have not yet used this, but it certainly adds value. Plus you get some Xamarin swag during the process.</p>
<p>The future will tell if the recertification process is worth it as well. So until then, I would suggest to join Xamarin University if you haven’t made up your mind yet.</p>Tim KlingeleersI’ve been using Xamarin University since april this year. My primary goal was to use it for certification purposes. The certification process requires you to follow several live classes where instructors go through the material using GoToMeeting. You can skip some of the required classes by taking an assessment exam. Assessment exam When you have some experience with Xamarin, you can consider skipping some 100-level classes by taking an assessment exam. I went through all the required video’s for the assessment at a playback speed of 2x to glance through the material quickly. This gave me a solid idea about what level of knowledge would be required to pass the assessment exam.Xamarin Native vs Xamarin Forms2016-01-22T14:20:11+00:002016-01-22T14:20:11+00:00https://tim.klingeleers.be/2016/01/22/xamarin-native-vs-xamarin-forms<p>Choosing the right tool for the job is always a tricky task. There are so many things to take into consideration. The saying “choosing is losing” is certainly applicable here. Every choice has its pro’s and con’s, and as a colleague said: “you will always be looking for the one thing that’s harder to do in the choice you made”. All it boils down to is making a choice, and sticking to it for a while. Since development lifecycles go so fast, expecially open-source, there might even be a better choice by tomorrow. This can create something we all know as “developers block”, not being able to deliver a single thing. And you will drive yourself crazy over all the options. Same goes for the choice between Xamarin or other platforms, and even for choices within the Xamarin platform itself. In this case the choice between Xamarin Native vs Xamarin Forms.</p>
<!--more-->
<p>At my current employer every team member has a solid .Net background, so the choice for Xamarin is something that came naturally. React Native was considered for a while, but the Javascript knowledge wasn’t as solid for everyone. Now I had to make a choice between Xamarin <a href="https://xamarin.com/forms" target="_blank">Forms</a> and Xamarin <a href="https://xamarin.com/platform" target="_blank">Native</a> for our daily development tasks. Our mission is to be “quick and efficient”, so while the looks of an app are still important they are not the main factor to consider. We also wanted to use the MVVM architecture (Model – View – ViewModel) in most of our apps. So that had be taken into consideration as well.</p>
<p>According to Xamarin you should consider 20% of your application to be shared code with Xamarin Native, while that becomes 80% shared code with Xamarin Forms. These numbers are just a rule of thumb, so your mileage may vary.</p>
<h3 id="xamarin-native">Xamarin Native</h3>
<p>Xamarin Native clearly has a couple of advantages for someone who has specific platform knowledge.</p>
<h4 id="reuse-platform-knowledge">Reuse platform knowledge</h4>
<p>Being able to build things as you would in the “normal way” for every platform is something that is very powerful in itself. If you have been developing apps for iOS with Swift or Objective-C for a while, it is very easy to reuse that knowledge.</p>
<p>However, this also leads to the fact that you need a thorough understanding of all 3 major platforms. iOS for example uses a completely different way of describing layout than Android or Windows Phone does, which has a steep learning curve to do correctly. So this is not something every developer in a team can pick up easily. Knowing everything about Intents (Android), Fragments (Android), ViewControllers (iOS), Segues (iOS) and all the other platform specific terms is very time consuming. When you haven’t touched a platform for a while, that knowledge is also pushed to the background, making it even harder.</p>
<h4 id="create-pixel-perfect-uis">Create pixel-perfect UI’s</h4>
<p>Xamarin Native makes it possible to create pixel-perfect UI’s, since the UI’s are being created specifically for each platform to support. Much more sophisticated animations are possible as well. But you need to have the knowledge of all the platforms.</p>
<h4 id="mvvm-frameworks">MVVM frameworks</h4>
<p>If you are committed to using Xamarin Native, and you want to use MVVM you have yet another choice to make. There are many MVVM frameworks available, that all have their pro’s and con’s as well. Some of the more popular are <a href="https://github.com/MvvmCross/MvvmCross" target="_blank">MvvmCross</a> (steep learning curve, but seems to be the most popular), <a href="http://www.mvvmlight.net/doc" target="_blank">MvvmLight</a> (which is not on GitHub but on Codeplex, which is unfortunate), <a href="http://reactiveui.net/" target="_blank">ReactiveUI</a> or if you just want bindings there is <a href="https://github.com/praeclarum/Bind" target="_blank">Bind</a>.</p>
<h3 id="xamarin-forms">Xamarin Forms</h3>
<p>For those of us who have been around long enough to see the first version of Xamarin Forms, it might have been a let-down to see what Xamarin Forms meant in the early stages. Some of us have formed an opinion about it and never reconsidered to use it again. But Xamarin made real progression lately, making it worth to reconsider once more.</p>
<h4 id="faster-development">Faster development</h4>
<p>The big difference between Native and Forms is that you can define your UI once, in a language many .Net developers are familiar with from WPF: XAML. While it can be quite challenging to learn the XAML language, it can be a game changer. Writing the UI once (for the most part, more on that later), and running it on every platform, is something that can appeal to many businesses. The context switch between the platforms is much less frequent, so you can focus more on the task at hand instead of platform specific implementation details.</p>
<h4 id="platforms-going-their-own-direction">Platforms going their own direction</h4>
<p>The challenge that Xamarin Forms has, is being able to make a common metaphor for all platform specific implementations. For the moment it is managed quite well. But who knows what the future will bring.</p>
<h4 id="yet-another-abstraction-layer">Yet another abstraction layer</h4>
<p>Xamarin itself can be seen as an abstraction layer. But Xamarin Forms creates another abstraction layer on top of that, which can contain other unexpected bugs. When you encounter such a bug, all gains in development speed can be cancelled when trying to fix it or finding a workaround. The big problem in my opinion is that Xamarin Forms is not open source. So you have to rely on the Xamarin developers to fix the issues and work around them for the time being. I have only been in this situation once until now (where a WebView wasn’t scaled properly when the device’s orientation changed on iOS). The community and the forum can be really helpful in this case.</p>
<p>This abstraction layer does not prevent you to get to the platform specific code by using Renderers and Services with Dependency Injection. So you can still implement parts of your Xamarin Forms app with Native implementations.</p>
<h4 id="many-plugins-available">Many plugins available</h4>
<p>Xamarin Forms has an open-source initiative by the name of <a href="https://github.com/XLabs/Xamarin-Forms-Labs" target="_blank">XLabs</a> that makes it easy to implement things that aren’t supplied by Xamarin Forms itself. Think about accelerometer or camera services for example. While the Xamarin Forms Labs plugins certainly have their issues (251 open issues at the time of writing), you can help by submitting Pull Requests. It can take some time before a PR is merged, but helping the community is always good (see <a href="https://github.com/XLabs/Xamarin-Forms-Labs/pull/1002" target="_blank">one of my PRs</a> for an example).</p>
<p>There are also lot’s of plugins available that are not part of Xamarin Forms Labs.</p>
<h4 id="mvvm">MVVM</h4>
<p>Xamarin Forms has been built to be able to use the standard ICommand’s, NotifyPropertyChanged events and so on to support MVVM out of the box. While you can still use other MVVM frameworks like <a href="https://github.com/MvvmCross/MvvmCross" target="_blank">MvvmCross</a> of <a href="http://brianlagunas.com/prism-for-xamarin-forms-6-2-0-preview-3/" target="_blank">Prism Forms</a>, there is no absolute need for it. Prism Forms is worth taking a look at, since it’s footprint is so small, it’s very easy to get started with.</p>
<h4 id="updated-frequently">Updated frequently</h4>
<p>The Xamarin Forms release cycle has improved a lot over it’s lifetime. WIth the release of <a href="https://developer.xamarin.com/releases/xamarin-forms/xamarin-forms-2.0/2.0.0/" target="_blank">version 2.0</a> just lately, and their <a href="https://github.com/xamarin/sport" target="_blank">Sport showcase app</a>, the potential of the platform is illustrated nicely with 93% of shared code. The <a href="https://developer.xamarin.com/releases/xamarin-forms/xamarin-forms-2.1/2.1.0-pre1/" target="_blank">release notes for the preview</a> of Xamarin Forms 2.1 are already available as well, which shows another nice set of enhancements to the platform.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Both Xamarin Native and Xamarin Forms have their pro’s and con’s. For my employers needs, we have taken the plunge to use Xamarin Forms for at least a couple of months and evaluate and reconsider after we have completed a few projects using the technology. The development speed that can be achieved for internal applications where UI is less important (not unimportant!), is the big selling point for now.</p>
<p>When your priority is to have absolute control over how your app looks, Xamarin Forms is not for you. Or if you only need to support a single platform, you might be better off using Xamarin Native. In this case I would even reconsider the usage of Xamarin altogether.</p>
<p>So is Xamarin Native better than Forms or vice versa? In my opinion: no. They both have their usages and will always co-exist.</p>Tim KlingeleersMaking a choice is always difficult. How about Xamarin Native vs Xamarin Forms? Is choosing really losing or is there a best of both worlds?