<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Miroslav Bajtoš</title>
    <description>The latest articles on DEV Community by Miroslav Bajtoš (@bajtos).</description>
    <link>https://dev.to/bajtos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F223184%2F7ef2232c-a6e6-43c2-b846-387f13216736.jpg</url>
      <title>DEV Community: Miroslav Bajtoš</title>
      <link>https://dev.to/bajtos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bajtos"/>
    <language>en</language>
    <item>
      <title>Privacy-friendly web analytics that works in the Brave browser</title>
      <dc:creator>Miroslav Bajtoš</dc:creator>
      <pubDate>Tue, 01 Feb 2022 09:44:05 +0000</pubDate>
      <link>https://dev.to/bajtos/privacy-friendly-web-analytics-that-works-in-the-brave-browser-5e9h</link>
      <guid>https://dev.to/bajtos/privacy-friendly-web-analytics-that-works-in-the-brave-browser-5e9h</guid>
      <description>&lt;p&gt;For my blog, I have the following requirements for web analytics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Respect the privacy of my readers. Don't let Big Tech track their behaviour&lt;br&gt;
and link it with other online activities. (Looking at you, Google Analytics!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Collect website visits from tech-savvy users. The Brave browser and various&lt;br&gt;
ad-block plugins are automatically blocking requests to well-known web&lt;br&gt;
analytics API backends.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nice to have: Don't mix real visitors with page visits I make while&lt;br&gt;
previewing a new version of my site.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I was able to get all these features from &lt;a href="https://plausible.io/"&gt;Plausible&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Plausible is extremely focused on privacy. They are minimizing data&lt;br&gt;
collection and don't collect any personal information. There are no cookies,&lt;br&gt;
no tracking across devices, websites or apps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plausible offers a well-documented solution for using a proxy to avoid&lt;br&gt;
content blockers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After a bit of searching, I found an easy way how to customize which domain&lt;br&gt;
name is reported by my website. This way I can distinguish between visits to&lt;br&gt;
the live website and preview sites.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  My setup
&lt;/h2&gt;

&lt;p&gt;I am using &lt;a href="https://gohugo.io"&gt;Hugo&lt;/a&gt; for generating my website and&lt;br&gt;
&lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; to build &amp;amp; serve the content. Here is how I&lt;br&gt;
implemented tracking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In my Hugo templates, I added a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag to fetch Plausible client-side
script. To avoid content-blockers, I am fetching the script from an URL on my
own domain: &lt;a href="///s/main.js"&gt;/s/main.js&lt;/a&gt;. Under the hood, Netlify handles this
endpoint by fetching the response from Plausible.&lt;/li&gt;
&lt;li&gt;I configured the Plausible client to post events to an URL on my own domain
too: &lt;a href="https://dev.to/s/event"&gt;/s/event&lt;/a&gt;. This endpoint is again proxied by Netlify to
Plausible.&lt;/li&gt;
&lt;li&gt;Finally, I have a small script to detect Netlify preview domains and tell the
Plausible client to report a different domain name to the data collector.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's start with the script setting up Plausible client. I am adding it as the&lt;br&gt;
last child of the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element in all my pages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bajtos.net&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bajtos.net&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preview.bajtos.net&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Where to fetch Plausible client-side script from&lt;/span&gt;
  &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/s/main.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Where to post events to&lt;/span&gt;
  &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/s/event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// What site to report&lt;/span&gt;
  &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-domain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the relevant part of my &lt;code&gt;netlify.toml&lt;/code&gt; file where I configure proxy&lt;br&gt;
rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[redirects]]&lt;/span&gt;
  &lt;span class="py"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/s/main.js"&lt;/span&gt;
  &lt;span class="py"&gt;to&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://plausible.io/js/plausible.js"&lt;/span&gt;
  &lt;span class="py"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;

&lt;span class="nn"&gt;[[redirects]]&lt;/span&gt;
  &lt;span class="py"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/s/event"&lt;/span&gt;
  &lt;span class="py"&gt;to&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://plausible.io/api/event"&lt;/span&gt;
  &lt;span class="py"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;202&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty simple, isn't it?&lt;/p&gt;

&lt;p&gt;You can learn more about Plausible in their docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://plausible.io/privacy-focused-web-analytics"&gt;Plausible: Privacy focused Google Analytics alternative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://plausible.io/docs/proxy/introduction"&gt;Adblockers and using a proxy for analytics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>analytics</category>
      <category>privacy</category>
      <category>brave</category>
      <category>blocker</category>
    </item>
    <item>
      <title>Android Emulator on Apple M1 machines</title>
      <dc:creator>Miroslav Bajtoš</dc:creator>
      <pubDate>Tue, 11 Jan 2022 10:03:46 +0000</pubDate>
      <link>https://dev.to/bajtos/android-emulator-on-apple-m1-machines-2p1p</link>
      <guid>https://dev.to/bajtos/android-emulator-on-apple-m1-machines-2p1p</guid>
      <description>&lt;p&gt;What options do we have for running Android apps on macOS?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android Studio&lt;/li&gt;
&lt;li&gt;BlueStacks&lt;/li&gt;
&lt;li&gt;Android SDK CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Android Studio is a large application built on top of IntelliJ IDE with a download size of over 900 MiB. That's a lot to install and keep up to date when all we need is an emulator!&lt;/p&gt;

&lt;p&gt;In the past, I have had a good experience with BlueStacks (which is still a medium-sized app). Unfortunately, they don't support Mac computers with M1 chips and macOS 12 Monterey.&lt;/p&gt;

&lt;p&gt;Fortunately, setting up Android Emulator via CLI is easier than I expected:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Java runtime&lt;/li&gt;
&lt;li&gt;Install Android SDK&lt;/li&gt;
&lt;li&gt;Download Android Emulator and Android system components&lt;/li&gt;
&lt;li&gt;Create a new virtual device&lt;/li&gt;
&lt;li&gt;Done!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Java runtime
&lt;/h2&gt;

&lt;p&gt;Android tooling is built in Java, therefore you need Java runtime installed on your machine. Using &lt;a href="https://brew.sh"&gt;Homebrew&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;openjdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's verify that our Java runtime is native M1. Inspect the executabl using &lt;code&gt;file&lt;/code&gt; command and check the architecture is &lt;code&gt;arm64&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ file /opt/homebrew/opt/openjdk/bin/java
/opt/homebrew/opt/openjdk/bin/java: Mach-O 64-bit executable arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Android SDK
&lt;/h2&gt;

&lt;p&gt;Android SDK is a set of CLI tools for building Android applications.  Importantly, it includes the tool called &lt;code&gt;sdkmanager&lt;/code&gt; which can download additional components. We will use this tool to install the emulator component, system images to boot the emulator and other required packages.&lt;/p&gt;

&lt;p&gt;For better or worse, the process to install command line tools only is manual.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download a ZIP file with the tools from the &lt;a href="https://developer.android.com/studio#command-tools"&gt;Android Studio homepage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;While there are two different builds of Android Studio for Intel and M1 chips, there is a single download for command-line tools. No need to worry!  Command-line tools are shell scripts delegating platform-specific work to Java.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extract the content of the archive to the &lt;code&gt;Library&lt;/code&gt; folder in your home directory. Typically, Safari will extract the ZIP archive into your Downloads folder. All you need is to move the files to the right place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's important to place the files in the exact path shown below, as some Android tools make assumptions about the file system layout.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/Library/Android/sdk/cmdline-tools/latest
 &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; ~/Downloads/cmdline-tools/&lt;span class="k"&gt;*&lt;/span&gt; ~/Library/Android/sdk/cmdline-tools/latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, update your &lt;code&gt;PATH&lt;/code&gt; environment variable to include Android tooling. Add the following block to your &lt;code&gt;~/.zsh&lt;/code&gt; or &lt;code&gt;~/.bashrc&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANDROID_SDK_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/Library/Android/sdk
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$ANDROID_SDK_ROOT&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_SDK_ROOT&lt;/span&gt;&lt;span class="s2"&gt;/cmdline-tools/latest/bin:&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_SDK_ROOT&lt;/span&gt;&lt;span class="s2"&gt;/emulator:&lt;/span&gt;&lt;span class="nv"&gt;$ANDROID_SDK_ROOT&lt;/span&gt;&lt;span class="s2"&gt;/platform-tools:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we can verify that &lt;code&gt;sdkmanager&lt;/code&gt; works:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;sdkmanager &lt;span class="nt"&gt;--version&lt;/span&gt;
5.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Android Emulator
&lt;/h2&gt;

&lt;p&gt;With the necessary tooling installed, the next step is to download various Android components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;sdkmanager &lt;span class="s2"&gt;"platform-tools"&lt;/span&gt; &lt;span class="s2"&gt;"emulator"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"platforms;android-30"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"system-images;android-30;google_apis_playstore;arm64-v8a"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will install the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;platform-tools&lt;/code&gt;: quoting the description from &lt;a href="https://developer.android.com/studio/releases/platform-tools"&gt;Android docs&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Android SDK Platform-Tools is a component for the Android SDK. It includes&lt;br&gt;
tools that interface with the Android platform, such as &lt;code&gt;adb&lt;/code&gt;, &lt;code&gt;fastboot&lt;/code&gt;,&lt;br&gt;
and &lt;code&gt;systrace&lt;/code&gt;. These tools are required for Android app development.&lt;br&gt;
They're also needed if you want to unlock your device bootloader and flash&lt;br&gt;
it with a new system image.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;emulator&lt;/code&gt;: a program that simulates Android devices on your computer and provides almost all of the capabilities of a real Android device.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;system-images;android-30;google_apis_playstore;arm64-v8a&lt;/code&gt;: system image for arm64 (Apple M1) platform, including access to Google Play Services and Google Play Store. The number 30 refers to API level, here we are picking Android 11 (API level 30). This image is required by the emulator to boot Android OS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;platforms;android-30&lt;/code&gt;: the SDK Platform is required to compile apps.  Apparently, the emulator requires it too. It's important to pick the same API level you choose for the system image (&lt;code&gt;android-30&lt;/code&gt; in my case).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Virtual device
&lt;/h2&gt;

&lt;p&gt;Now we can create a virtual Android device to run in the emulator. Notice the &lt;code&gt;package&lt;/code&gt; value -- it's the name of the system image you downloaded via &lt;code&gt;sdkmanager&lt;/code&gt; in the previous step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;avdmanager create avd &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"android30"&lt;/span&gt; &lt;span class="nt"&gt;--device&lt;/span&gt; &lt;span class="s2"&gt;"pixel"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--package&lt;/span&gt; &lt;span class="s2"&gt;"system-images;android-30;google_apis_playstore;arm64-v8a"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can create as many virtual devices as you like. Just repeat the step above with different parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start the emulator
&lt;/h2&gt;

&lt;p&gt;Here comes the easiest part: start the emulator using the name of the virtual device created in the previous step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;emulator &lt;span class="nt"&gt;-avd&lt;/span&gt; android30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations, you have a working Android Emulator now and can run any Android applications you like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonuses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Enable hardware keyboard
&lt;/h3&gt;

&lt;p&gt;By default, the emulator offers an on-screen keyboard for touch typing. This works great on mobile phones with touch screens, but not so much on a MacBook with no touch support! The process of logging into your Google account without a proper keyboard is rather frustrating.&lt;/p&gt;

&lt;p&gt;Fortunately, the emulator can accept input from your computer keyboard. Just enable hardware keyboard in your virtual device config which is stored in &lt;code&gt;~/.android/avd/android30.avd/config.ini&lt;/code&gt; (replace &lt;code&gt;android30&lt;/code&gt; with the name of your device).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- hw.keyboard = no
&lt;/span&gt;&lt;span class="gi"&gt;+ hw.keyboard = yes
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install applications from APK files
&lt;/h3&gt;

&lt;p&gt;If you choose a system image that includes Play Store, then you can install Android applications directly from the official app store.&lt;/p&gt;

&lt;p&gt;Either way, you can also install applications from APK files. Run the following command while the emulator is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;adb &lt;span class="nb"&gt;install &lt;/span&gt;my-app.apk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>android</category>
      <category>macos</category>
      <category>m1</category>
      <category>emulator</category>
    </item>
  </channel>
</rss>
