<?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: Marcos Placona</title>
    <description>The latest articles on DEV Community by Marcos Placona (@mplacona).</description>
    <link>https://dev.to/mplacona</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%2F1742%2F221627.png</url>
      <title>DEV Community: Marcos Placona</title>
      <link>https://dev.to/mplacona</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mplacona"/>
    <language>en</language>
    <item>
      <title>How I Built a SaaS in a Weekend That Replaces Google Alerts</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Sat, 21 Mar 2026 08:40:01 +0000</pubDate>
      <link>https://dev.to/mplacona/how-i-built-a-saas-in-a-weekend-that-replaces-google-alerts-240d</link>
      <guid>https://dev.to/mplacona/how-i-built-a-saas-in-a-weekend-that-replaces-google-alerts-240d</guid>
      <description>&lt;p&gt;Google Alerts has been broken for years. It misses most mentions, delivers them days late, and gives you zero context about what was said. I know because I tracked it. Out of 10 real mentions of my brand in a week, Google Alerts caught 2.&lt;/p&gt;

&lt;p&gt;The paid alternatives (Mention, Brand24) start at $99+/mo and are built for enterprise marketing teams. There's nothing in between for indie founders, freelancers, or small businesses.&lt;/p&gt;

&lt;p&gt;So I built MentionDrop. Real-time web mention monitoring with AI summaries, for $29/mo. Here's how I did it in a weekend.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/cSpFVgb8s8E"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem I Kept Running Into
&lt;/h2&gt;

&lt;p&gt;Someone trashed one of my products on a niche forum. I found out two weeks later when a friend sent me the link. Google Alerts never picked it up. By then, the thread had 40+ replies, and the narrative was set.&lt;/p&gt;

&lt;p&gt;That was the last straw. I needed something that actually monitored the web in real-time and told me what was being said, not just that a keyword appeared on a page somewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;I optimized for speed-to-launch. Every tool in the stack was chosen because I could go from zero to working in minutes, not days.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Next.js (App Router)&lt;/td&gt;
&lt;td&gt;Fast to ship, great DX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;shadcn/ui + Tailwind&lt;/td&gt;
&lt;td&gt;Beautiful components without designing from scratch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Clerk&lt;/td&gt;
&lt;td&gt;5 minutes to add login, social auth, user management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Supabase (Postgres)&lt;/td&gt;
&lt;td&gt;Free tier is generous, instant API, real-time subscriptions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;td&gt;Checkout, billing portal, webhooks out of the box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Gemini Flash-Lite&lt;/td&gt;
&lt;td&gt;Cheap, fast, good enough for summarization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;Resend + React Email&lt;/td&gt;
&lt;td&gt;Developer-friendly transactional email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worker hosting&lt;/td&gt;
&lt;td&gt;Railway&lt;/td&gt;
&lt;td&gt;$2/mo for a background process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend hosting&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;Free tier for Next.js&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Total infrastructure cost: under $5/mo to start. That matters when you're validating an idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works (High Level)
&lt;/h2&gt;

&lt;p&gt;The architecture is two processes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Next.js app&lt;/strong&gt; on Vercel - the landing page, dashboard, and API routes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background worker&lt;/strong&gt; on Railway - connects to a real-time data source, matches keywords, runs AI analysis, and stores results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When a user adds a keyword, the worker picks it up within seconds and starts monitoring. When a match is found, the AI processes it, and the user is notified via their preferred channel (email, Slack, or webhook).&lt;/p&gt;

&lt;p&gt;The dashboard streams mentions in real-time via Supabase's real-time subscriptions, so you see new mentions appear without refreshing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hardest Problem: Noise
&lt;/h2&gt;

&lt;p&gt;Matching a keyword against web content sounds simple until you realize how noisy it is. One of the first companies to sign up was Box. "Box" matches every page that mentions a cardboard box. "Apple" matches every recipe blog. "Circle" matches geometry tutorials.&lt;/p&gt;

&lt;p&gt;This is the problem Google Alerts has and has never solved. They dump everything on you and call it a day.&lt;/p&gt;

&lt;p&gt;I spent most of my time on this problem. The solution involves multiple layers of filtering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keyword-level rules&lt;/strong&gt; that understand short generic terms need stricter matching than longer, more specific ones&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-powered relevance scoring&lt;/strong&gt; that understands context. "Is this page about Box, the cloud storage company, or a shipping box?" The AI decides.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User-provided context&lt;/strong&gt; - you can tell MentionDrop "Box is a cloud storage company, competitor to Dropbox," and it uses that to make better decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result: irrelevant matches get filtered out before they ever reach you. When you get an alert, it's because something actually matters.&lt;/p&gt;

&lt;p&gt;Each mention comes with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plain-English summary (even if the source is in another language)&lt;/li&gt;
&lt;li&gt;Sentiment analysis (positive/neutral/negative)&lt;/li&gt;
&lt;li&gt;A suggested action (respond, share, monitor, or ignore)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons From Building in a Weekend
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Clerk saved me hours.&lt;/strong&gt; Auth is one of those things that seems simple but has a million edge cases. Clerk handles login, signup, OAuth, user management, and webhooks. I had the auth working in under 10 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supabase real-time is magic for dashboards.&lt;/strong&gt; Instead of polling for new mentions, I use Supabase's real-time subscriptions. When the worker stores a new mention, it appears on the dashboard instantly. Zero extra code on the frontend beyond subscribing to the table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Railway is perfect for background workers.&lt;/strong&gt; I needed a long-running process that stays connected to a data stream 24/7. Railway runs it for $2/mo. No Docker config, no Kubernetes, just &lt;code&gt;npx tsx src/worker/consumer.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start with fewer features.&lt;/strong&gt; The dashboard has filtering by keyword, sentiment, date range, and live streaming. I could have launched with just an email digest and a simple list page. Ship the minimum, then iterate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resend + React Email is the way.&lt;/strong&gt; I write email templates in JSX with proper TypeScript props. No more wrestling with HTML email tables. The developer experience is a night-and-day difference compared to other email services.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build time:&lt;/strong&gt; 1 weekend (with AI assistance for code generation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure cost:&lt;/strong&gt; ~$5/mo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing:&lt;/strong&gt; Free (1 keyword), $29/mo (5 keywords), $59/mo (20 keywords)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests:&lt;/strong&gt; 100+ passing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I'm working on improving the AI accuracy for multi-language mentions and adding more alert delivery options. The core product is solid, and I'm getting real users finding real mentions that Google Alerts would have missed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;If you've ever been frustrated by Google Alerts missing mentions of your brand, product, or name, give MentionDrop a try. Free tier, 1 keyword, no credit card needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mentiondrop.com" rel="noopener noreferrer"&gt;mentiondrop.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy to answer any questions about the build process, stack choices, or business decisions in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>saas</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Built a Tool to Finally Understand What Works on LinkedIn Company Pages</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Tue, 14 Oct 2025 13:28:00 +0000</pubDate>
      <link>https://dev.to/mplacona/i-built-a-tool-to-finally-understand-what-works-on-linkedin-company-pages-92i</link>
      <guid>https://dev.to/mplacona/i-built-a-tool-to-finally-understand-what-works-on-linkedin-company-pages-92i</guid>
      <description>&lt;p&gt;If you’ve ever managed a LinkedIn Company Page, you know how frustrating the analytics are.&lt;/p&gt;

&lt;p&gt;You get &lt;em&gt;some&lt;/em&gt; numbers, but not enough to actually make decisions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which posts really drive engagement?&lt;/li&gt;
&lt;li&gt;What time works best to post?&lt;/li&gt;
&lt;li&gt;Who exactly is following your page?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I got tired of guessing. So I built &lt;a href="https://getlinkintel.com" rel="noopener noreferrer"&gt;&lt;strong&gt;LinkIntel&lt;/strong&gt;&lt;/a&gt; — a tool that goes beyond LinkedIn’s native analytics to show real insights from your exported data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I run multiple projects where LinkedIn is our main growth channel.&lt;br&gt;
But every time I wanted to analyze performance, I ended up in Excel hell:&lt;br&gt;
exporting CSVs, merging them, cleaning columns, and still not knowing which content &lt;em&gt;actually worked.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;LinkedIn’s built-in analytics dashboard is decent for a quick look — but it hides trends that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which post types consistently perform best&lt;/li&gt;
&lt;li&gt;When your audience is most active&lt;/li&gt;
&lt;li&gt;How your audience demographics evolve over time&lt;/li&gt;
&lt;li&gt;How you compare against competitors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted something clearer, faster, and owned by me — no APIs, no permissions, no data sharing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What LinkIntel does
&lt;/h2&gt;

&lt;p&gt;LinkIntel takes your exported LinkedIn analytics files and turns them into beautiful, interactive dashboards.&lt;br&gt;
It supports four types of exports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content Analytics&lt;/strong&gt; – see which posts drive impressions, engagement, and clicks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follower Analytics&lt;/strong&gt; – understand your audience by location, seniority, and job function&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visitor Analytics&lt;/strong&gt; – learn who’s visiting your page and from which companies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitor Analytics&lt;/strong&gt; – benchmark your performance against others in your space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You upload your files once, and within seconds you get charts, insights, and benchmarks — no setup required.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes it different
&lt;/h2&gt;

&lt;p&gt;Unlike other tools, LinkIntel doesn’t rely on LinkedIn’s API.&lt;br&gt;
You stay in control of your data — it’s 100% yours, processed locally and never shared.&lt;/p&gt;

&lt;p&gt;It’s built for &lt;strong&gt;B2B marketing teams, agencies, and founders&lt;/strong&gt; who care about making data-driven decisions without losing ownership or privacy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;Right now, I’m talking directly to users one-on-one to learn what they need most — from smarter insights to AI recommendations on what to post next.&lt;/p&gt;

&lt;p&gt;If you run a LinkedIn Page and want to understand what &lt;em&gt;actually drives results,&lt;/em&gt; you can try it for free at &lt;a href="https://getlinkintel.com" rel="noopener noreferrer"&gt;&lt;strong&gt;getlinkintel.com&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stop guessing. Start learning what really works on LinkedIn.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>marketing</category>
      <category>linkedin</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Building a video recording application in Android with CameraX</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Mon, 27 May 2019 10:41:43 +0000</pubDate>
      <link>https://dev.to/mplacona/building-a-video-recording-application-in-android-with-camerax-2ibb</link>
      <guid>https://dev.to/mplacona/building-a-video-recording-application-in-android-with-camerax-2ibb</guid>
      <description>&lt;p&gt;Recording videos in Android used to be a very involved task where it was necessary to write a lot of boilerplate code to initialise the camera and then keep control of the video state and its metadata.&lt;/p&gt;

&lt;p&gt;With the introduction of &lt;a href="https://developer.android.com/jetpack/androidx/releases/camerax"&gt;CameraX&lt;/a&gt; to &lt;a href="https://developer.android.com/jetpack"&gt;Android Jetpack&lt;/a&gt;, it only takes a few lines of code to get that going. Let’s build a video recording application.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;You can download the code for this project in &lt;a href="https://github.com/mplacona/Droidagram"&gt;this repository&lt;/a&gt; if you just want to see it running and not follow along.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In Android Studio create a new project with an empty activity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zwt2Qkdb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://placona.co.uk/images/2019/05/camerax-01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zwt2Qkdb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://placona.co.uk/images/2019/05/camerax-01.png" alt="new android application screen" width="880" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen give your project a name, I called mine &lt;code&gt;Droidagram&lt;/code&gt; and made sure to check the &lt;code&gt;Use androidx.* artifacts&lt;/code&gt;. I will be using Kotlin here, but you should feel free to use Java if you like typing more code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1M3ZoBFQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://placona.co.uk/images/2019/05/camerax-02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1M3ZoBFQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://placona.co.uk/images/2019/05/camerax-02.png" alt="new android application screen" width="880" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open up your &lt;code&gt;AndroidManifest.xml&lt;/code&gt; and add the following just before the &lt;code&gt;&amp;lt;application&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;uses-permission android:name="android.permission.CAMERA" /&amp;gt;
&amp;lt;uses-permission android:name="android.permission.RECORD_AUDIO" /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes sure that we request the correct permissions to open up the camera and record audio on the device.&lt;/p&gt;

&lt;p&gt;Open your module level &lt;code&gt;build.gradle&lt;/code&gt; and add the following dependencies and sync:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def camerax_version = "1.0.0-alpha01"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the time of writing “1.0.0-alpha01” is the latest version of CameraX, so make sure you check &lt;a href="https://mvnrepository.com/artifact/androidx.camera/camera-core"&gt;here&lt;/a&gt; for a more up-to-date version, though keep in mind that it may break the code you see here.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;activity_main.xml&lt;/code&gt; and on the XML view add a &lt;code&gt;TextureView&lt;/code&gt; and an &lt;code&gt;ImageButton&lt;/code&gt; instead of the existing &lt;code&gt;TextView&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;&amp;lt;TextureView
            android:id="@+id/view_finder"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent" /&amp;gt;

    &amp;lt;ImageButton
            android:layout_width="72dp"
            android:layout_height="72dp" app:srcCompat="@android:drawable/ic_menu_camera"
            android:id="@+id/capture_button" android:layout_marginBottom="24dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
            android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/view_finder"
            app:layout_constraintHorizontal_bias="0.498" app:layout_constraintVertical_bias="0.748"
            android:background="#F44336"/&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run this application now you will see something similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vb9nNc2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://placona.co.uk/images/2019/05/camerax-03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vb9nNc2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://placona.co.uk/images/2019/05/camerax-03.png" alt="First run of the video recording app" width="270" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Adding the camera preview
&lt;/h1&gt;

&lt;p&gt;To be able to preview the camera, we need to request the permissions first. We do that going to &lt;code&gt;MainActivity.kt&lt;/code&gt; and adding a couple of constants just before our &lt;code&gt;class&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;private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
private val tag = MainActivity::class.java.simpleName

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The number 10 here is just an arbitrary number we are using to keep track of the permission, and then we have an array with our required permissions which matches what we’ve added to our manifest earlier. Just make sure you import &lt;code&gt;Manifest&lt;/code&gt; from &lt;code&gt;import android.Manifest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let’s change this class so it also implements &lt;code&gt;LifecycleOwner&lt;/code&gt; as we will need to bind our camera to it later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MainActivity : AppCompatActivity(), LifecycleOwner {

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the class, and before &lt;code&gt;onCreate&lt;/code&gt; add the following &lt;code&gt;lateinit&lt;/code&gt; variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private lateinit var viewFinder: TextureView
private lateinit var captureButton: ImageButton
private lateinit var videoCapture: VideoCapture

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;onCreate&lt;/code&gt; and just after &lt;code&gt;setContentView&lt;/code&gt; add the following lines of code to start requesting permissions when this activity starts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;viewFinder = findViewById(R.id.view_finder)
captureButton = findViewById(R.id.capture_button)

// Request camera permissions
if (allPermissionsGranted()) {
    viewFinder.post { startCamera() }
} else {
    ActivityCompat.requestPermissions(
        this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that both &lt;code&gt;allPermissionsGranted&lt;/code&gt; and &lt;code&gt;startCamera&lt;/code&gt; are be showing in red on the IDE.&lt;/p&gt;

&lt;p&gt;At the bottom of the class, just after &lt;code&gt;onCreate&lt;/code&gt;, add the following three methods, and the error warnings disappear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;override fun onRequestPermissionsResult(
    requestCode: Int, permissions: Array&amp;lt;String&amp;gt;, grantResults: IntArray) {
    if (requestCode == REQUEST_CODE_PERMISSIONS) {
        if (allPermissionsGranted()) {
            viewFinder.post { startCamera() }
        } else {
            Toast.makeText(this,
                "Permissions not granted by the user.",
                Toast.LENGTH_SHORT).show()
            finish()
        }
    }
}

private fun allPermissionsGranted(): Boolean {
    for (permission in REQUIRED_PERMISSIONS) {
        if (ContextCompat.checkSelfPermission(
                this, permission) != PackageManager.PERMISSION_GRANTED) {
            return false
        }
    }
    return true
}

private fun startCamera() {
    TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first and second methods handle the permission request and the response once the user decides as to whether they accept that we can use the camera within our app. Make sure that if you run the application now, you say “allow” to both.&lt;/p&gt;

&lt;p&gt;Lastly, we’re going to add some code to display the camera preview on the screen for when we run the app.&lt;/p&gt;

&lt;p&gt;Remove the &lt;code&gt;TODO&lt;/code&gt; code from the &lt;code&gt;startCamera&lt;/code&gt; method and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create configuration object for the viewfinder use case
val previewConfig = PreviewConfig.Builder().build()
// Build the viewfinder use case
val preview = Preview(previewConfig)

preview.setOnPreviewOutputUpdateListener {
    viewFinder.surfaceTexture = it.surfaceTexture
}

// Bind use cases to lifecycle
CameraX.bindToLifecycle(this, preview)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above is all you need to preview the camera. If you run the application now, it turns the camera on for your device or emulator. Now is a good time to try this out and see if everything is configured correctly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Programming the button
&lt;/h1&gt;

&lt;p&gt;I wanted this button to only record when I held it pressed, and for it to stop recording when released. Let’s add this logic inside the &lt;code&gt;onCreate&lt;/code&gt; just before the end of the method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;captureButton.setOnTouchListener { _, event -&amp;gt;
    if (event.action == MotionEvent.ACTION_DOWN) {
        captureButton.setBackgroundColor(Color.GREEN)

    } else if (event.action == MotionEvent.ACTION_UP) {
        captureButton.setBackgroundColor(Color.RED)
    }
    false
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Holding the button changes the background colour of it, and releasing brings it back to its original colour.&lt;/p&gt;

&lt;h1&gt;
  
  
  Recording videos
&lt;/h1&gt;

&lt;p&gt;Now we’re ready to record our videos. Just before the logic for the button, add the following variable, so we get a location and a file name to save our recording.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val file = File(externalMediaDirs.first(),
            "${System.currentTimeMillis()}.mp4")

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we just need to change our button so when pressed, it also starts recording, and when released it stops the recording.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;captureButton.setOnTouchListener { _, event -&amp;gt;
    if (event.action == MotionEvent.ACTION_DOWN) {
        captureButton.setBackgroundColor(Color.GREEN)
        videoCapture.startRecording(file, object: VideoCapture.OnVideoSavedListener{
        override fun onVideoSaved(file: File?) {
            Log.i(tag, "Video File : $file")
        }
        override fun onError(useCaseError: VideoCapture.UseCaseError?, message: String?, cause: Throwable?) {
            Log.i(tag, "Video Error: $message")
        }
    })

    } else if (event.action == MotionEvent.ACTION_UP) {
        captureButton.setBackgroundColor(Color.RED)
        videoCapture.stopRecording()
        Log.i(tag, "Video File stopped")
    }
    false
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are running CameraX version &lt;code&gt;1.0.0-alpha01&lt;/code&gt; you will notice a red squiggly line under the &lt;code&gt;startRecording&lt;/code&gt; and &lt;code&gt;stopRecording&lt;/code&gt; methods. This is because this functionality is still highly experimental and likely to change and is still restricted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VUFRTVb_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://placona.co.uk/images/2019/05/camerax-04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VUFRTVb_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://placona.co.uk/images/2019/05/camerax-04.png" alt="Error with" width="880" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can tell the compiler to ignore those by adding the following to the top of this class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SuppressLint("RestrictedApi")
class MainActivity : AppCompatActivity(), LifecycleOwner {

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last thing we need to do is initialise the video recorder use-case, so when the camera is started, we tell it to get ready for some recording action. Head to the &lt;code&gt;startCamera&lt;/code&gt; method and just after &lt;code&gt;val preview = ...&lt;/code&gt; add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create a configuration object for the video use case
val videoCaptureConfig = VideoCaptureConfig.Builder().apply {
    setTargetRotation(viewFinder.display.rotation)
}.build()
videoCapture = VideoCapture(videoCaptureConfig)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a new configuration for the video capturing use-case and initialises the last uninitialised lateinit variable we had, which is called &lt;code&gt;videoCapture&lt;/code&gt;. Let’s also bind this to the lifecycle by changing it to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Bind use cases to lifecycle
CameraX.bindToLifecycle(this, preview, videoCapture)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the application and hold the record button, and your video will get saved to the filesystem as soon as you release it. You can check your recording out by going to &lt;code&gt;/storage/emulated/0/Android/media/[your.package.name]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So this is all it takes to use this great new addition to JetPack. Get recording and let me know what you think by hitting me up &lt;a href="https://twitter.com/marcos_placona"&gt;@marcos_placona&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>jetpack</category>
      <category>architecture</category>
      <category>android</category>
    </item>
    <item>
      <title>Handling your business calls and texts like a... boss!</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Thu, 28 Mar 2019 12:10:06 +0000</pubDate>
      <link>https://dev.to/twilio/handling-your-business-calls-and-texts-like-a-boss-283o</link>
      <guid>https://dev.to/twilio/handling-your-business-calls-and-texts-like-a-boss-283o</guid>
      <description>&lt;p&gt;I dread the idea of having ever to change my phone number. Be it because I'm getting spammed, or because someone thinks it's a good idea to call me during the night every night for the...rest...of...my...life. I'd much rather throw away all my business cards with a  disposable phone number than to dispose of my real phone number which I had for 15 years now.&lt;/p&gt;

&lt;p&gt;To make sure we never have to dispose of our real number, today we are going to look at how to provision new phone numbers that you can give out to people or put on your business cards without leaving the &lt;a href="https://www.twilio.com/console" rel="noopener noreferrer"&gt;Twilio Console&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Twilio account - you can get one for free &lt;a href="https://www.twilio.com/try-twilio" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(optional) A picture frame - because you're going to want to put your picture up looking like a boss when you finish this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Handling text messages
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is go to the &lt;a href="https://www.twilio.com/console/phone-numbers/incoming" rel="noopener noreferrer"&gt;phone numbers page&lt;/a&gt; and buy a phone number.&lt;/p&gt;

&lt;p&gt;The beauty of these numbers is that we can release them just as easily as we can get one, which ties well with the idea of never having to "release" the beloved phone numbers we've held for years.&lt;/p&gt;

&lt;p&gt;I chose a UK mobile number and then headed to the setup page. In that page and under "Messaging", select "TwiML" and press the "+" button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FmBHNjSz6ST-nJ62Y3hdTgM-uOCT1lmlaoSnsSSOBmWyVh7.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FmBHNjSz6ST-nJ62Y3hdTgM-uOCT1lmlaoSnsSSOBmWyVh7.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the modal window that the "+" button just opened, enter a name for your TwiML bin. I called mine "Business Card". Add the following code to handle incoming SMS messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;Response&amp;gt;
    &amp;lt;Message to="YOUR_PHONE_NUMBER"&amp;gt;
        {{From}}: {{Body}}
    &amp;lt;/Message&amp;gt;
&amp;lt;/Response&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the value &lt;code&gt;YOUR_PHONE_NUMBER&lt;/code&gt; with your actual mobile number so any incoming messages to your Twilio phone number get redirected to you and then hit save. You're done with this setup and ready to handle phone calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling text messages
&lt;/h2&gt;

&lt;p&gt;We could do the same thing we did above with phone calls and be done with it, but I like to treat people who call me directly a little better.&lt;/p&gt;

&lt;p&gt;Head to &lt;a href="https://www.twilio.com/console/runtime/overview" rel="noopener noreferrer"&gt;Runtime&lt;/a&gt; and create a new &lt;a href="https://www.twilio.com/docs/runtime/functions" rel="noopener noreferrer"&gt;Twilio Function&lt;/a&gt;. On the &lt;a href="https://www.twilio.com/console/runtime/functions/manage" rel="noopener noreferrer"&gt;Management&lt;/a&gt; page click the "+", choose "Blank" and click "Create". Give that a name – I called mine "Personal Voicemail" – and set the path to be "/personal-voicemail".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FXy1kRjVbRCMg0KlXW05vAbu9ZkNs4MVG2Ecwv62ZTAX_B6.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2FXy1kRjVbRCMg0KlXW05vAbu9ZkNs4MVG2Ecwv62ZTAX_B6.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We want to do a couple of things with this function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be able to answer calls to our Twilio number on our own number&lt;/li&gt;
&lt;li&gt;Block certain numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose "Incoming Voice Calls" under "Event" and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.handler = function (context, event, callback) {

        /***** configuration *****/

        const phoneNumber = 'YOUR_PHONE_NUMBER';
        const timeout = event.Timeout || 12;

        const secureRecordingLinks = false;

        const voiceOpts = {
                'voice': 'alice',
                'language': 'en-US'
        };

        const reject = [
                // To block a caller, add the E164 formatted number here
        ];

        let rejectMessage = "You are calling from a restricted number. Goodbye.";

        /***** end configuration *****/


        let thisFunction = 'https://' + context.DOMAIN_NAME + '/personal-voicemail';

        function shouldReject() {
                return reject.length &amp;amp;&amp;amp; event.From &amp;amp;&amp;amp; reject.includes(event.From);
        }

        function rejectInbound() {
                let twiml = new Twilio.twiml.VoiceResponse();
                if (rejectMessage) {
                        twiml.say(rejectMessage, voiceOpts);
                }
                twiml.hangup();
                return twiml;
        }

        function handleInbound() {
                const dialParams = {
                        'action': thisFunction
                };

                if (event.CallerId) {
                        dialParams.callerId = event.CallerId;
                }

                if (timeout) {
                        dialParams.timeout = timeout;
                }

                const twiml = new Twilio.twiml.VoiceResponse();
                twiml.dial(dialParams, phoneNumber);

                return twiml;
        }

        function redirect() {
                const twiml = new Twilio.twiml.VoiceResponse();
                twiml.redirect(thisFunction);
                return twiml;
        }

        switch (true) {
                case event.CallStatus === 'queued':
                        callback(null, redirect());
                        break;
                case event.CallStatus === 'ringing':
                        callback(null, shouldReject() ? rejectInbound() : handleInbound());
                        break;
                default:
                        callback();
        }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above check that the number calling your Twilio number is not in the blacklist and in that case will forward the call to your real telephone number.&lt;/p&gt;

&lt;p&gt;Make sure you replace the &lt;code&gt;YOUR_PHONE_NUMBER&lt;/code&gt; value with your actual mobile number. If you have any numbers you want to add to the blacklist, add them comma-delimited like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const reject = [
                "+123456789","+15555555","+44123456789"
        ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go back to the&lt;a href="https://www.twilio.com/console/phone-numbers/incoming" rel="noopener noreferrer"&gt; phone numbers page&lt;/a&gt;. Under "Voice &amp;amp; Fax" choose "Function" for "When a Call Comes in" and then select your new function and hit save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F93XjFtQkKcsepYj-WLkaHTBRmW0QrGf-sVe3eSBboozvZ5.width-500.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fcom.twilio.prod.twilio-docs%2Fimages%2F93XjFtQkKcsepYj-WLkaHTBRmW0QrGf-sVe3eSBboozvZ5.width-500.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When someone calls or texts your Twilio phone number, they should get redirected to your real phone number. You will then have the option to answer it or send straight to voicemail as you would normally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boss mode: Unlocked!
&lt;/h2&gt;

&lt;p&gt;Now that our number is safe from spam or abuse, we can rest assured knowing that if ever anyone gets hold of our Twilio number and decides to abuse it, we can always release it and get another one using the code we've already written.&lt;/p&gt;

&lt;p&gt;Furthermore, we can have several numbers using the same code so we can give them away at different occasions.&lt;/p&gt;

&lt;p&gt;I would love to hear about smart ways in which you use Twilio to make your life easier. Hit me up on &lt;a href="https://twitter.com/marcos_placona?lang=en" rel="noopener noreferrer"&gt;@marcos_placona&lt;/a&gt; or leave a comment below.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>business</category>
      <category>businesscard</category>
    </item>
    <item>
      <title>What is the one conference you do not want to miss in 2018?</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Fri, 26 Jan 2018 19:09:45 +0000</pubDate>
      <link>https://dev.to/mplacona/what-is-the-one-conference-you-do-not-want-to-miss-in-2018-2ahf</link>
      <guid>https://dev.to/mplacona/what-is-the-one-conference-you-do-not-want-to-miss-in-2018-2ahf</guid>
      <description>&lt;ul&gt;
&lt;li&gt;More than one event is totally fine&lt;/li&gt;
&lt;li&gt;Links to possible CFPs would be useful&lt;/li&gt;
&lt;li&gt;Conferences don't always need to be technical&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>conferences</category>
    </item>
    <item>
      <title>Building a fully featured burner phone with Kotlin</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Fri, 28 Jul 2017 12:37:09 +0000</pubDate>
      <link>https://dev.to/mplacona/building-a-fully-featured-burner-phone-with-kotlin</link>
      <guid>https://dev.to/mplacona/building-a-fully-featured-burner-phone-with-kotlin</guid>
      <description>&lt;p&gt;You walk into your favourite coffee shop and today they ask you if you’d like to register for a loyalty card. All they need is your name and phone number.&lt;/p&gt;

&lt;p&gt;On the way back you stop for groceries and the cashier asks if you’d like to enter a prize draw. All they need is your name and phone number.&lt;/p&gt;

&lt;p&gt;It’s finally time to put that lawn mower you’ve not used in years on Craigslist but at the end of the ad, it asks you to enter your phone number so buyers can contact you directly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FtAczNU_xh6czYFKDxwC2smcRLRUQwjL6IehMlfIZw1wSgDz0Zw-UU-gZ83CtTFQJNVBePv0zHyG5ykkYZMleGb6zQ0597kI1AsJurCTwHsiQtFyoYiWH1yzIq8WJVvbI9rRLauFt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FtAczNU_xh6czYFKDxwC2smcRLRUQwjL6IehMlfIZw1wSgDz0Zw-UU-gZ83CtTFQJNVBePv0zHyG5ykkYZMleGb6zQ0597kI1AsJurCTwHsiQtFyoYiWH1yzIq8WJVvbI9rRLauFt.png" alt="spam messages coming in"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  You need a burner phone!
&lt;/h2&gt;

&lt;p&gt;Let’s look at how we can use Kotlin and Twilio to build and deploy a burner phone application so that we can use multiple phone numbers for these situations. If you just want to download the code you can have a look at &lt;a href="https://github.com/mplacona/BurnerPhones" rel="noopener noreferrer"&gt;this repo&lt;/a&gt; or deploy it to Heroku using the button below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://heroku.com/deploy?template=https://github.com/mplacona/BurnerPhones/tree/master" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FrRESopN9OU-mG_8U4-m4Ltz-GneWE1HkYs0WEOVpZLb7XN-5h6sU0gUy7tzQc501sGJ7BivD0JfViasCuYVwB6uyKTL6wCGsARp0GT9ZkoHO6mRlq-Df80H8POJo7x6UOnAH_qnv.png" alt="Deploy to Heroku"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Our tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I will be using &lt;a href="https://www.jetbrains.com/idea/" rel="noopener noreferrer"&gt;IntelliJ IDEA&lt;/a&gt; for the code but feel free to use your preferred IDE as long as it works well with Gradle.&lt;/li&gt;
&lt;li&gt;One or multiple Twilio Phone numbers for creating various burner phones. You can &lt;a href="https://www.twilio.com/try-twilio" rel="noopener noreferrer"&gt;get them here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The project
&lt;/h2&gt;

&lt;p&gt;Let’s start by creating a new Gradle project in IntelliJ and adding Kotlin (Java) as the library.&lt;/p&gt;

&lt;p&gt;I have described the entire process in the first part of &lt;a href="https://www.twilio.com/blog/2017/05/send-and-receive-sms-messages-with-kotlin.html" rel="noopener noreferrer"&gt;Send and Receive SMS messages with Kotlin&lt;/a&gt;. You can follow it &lt;a href="https://www.twilio.com/blog/2017/05/send-and-receive-sms-messages-with-kotlin.html#kotlin-get-started" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Alternatively, you can just clone the repository as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:mplacona/BurnerPhones.git
cd BurnerPhones
git checkout starter-application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that project open on IntelliJ, start by right clicking on &lt;code&gt;App.kt&lt;/code&gt; and choosing “Run”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2Fs1zKnoqIiSRnbhRZeD8XMv0draOzy3uZ4H5xyIplW7ycTzzHodnSB86ODBWbPDk36u8ZwKTLPMdWJb_bew_ZPPgOWMHlrXK3oNvmlEGFTskKSaxfYAAJAD_34IugyViAF8RRZzPS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2Fs1zKnoqIiSRnbhRZeD8XMv0draOzy3uZ4H5xyIplW7ycTzzHodnSB86ODBWbPDk36u8ZwKTLPMdWJb_bew_ZPPgOWMHlrXK3oNvmlEGFTskKSaxfYAAJAD_34IugyViAF8RRZzPS.png" alt="Run Kotlin application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your browser go to &lt;a href="http://localhost:8080/sms/" rel="noopener noreferrer"&gt;http://localhost:8080/sms/&lt;/a&gt; and you will see the default controller displayed.&lt;br&gt;
Let’s change one configuration in &lt;code&gt;App.kt&lt;/code&gt; so the application knows where to forward the SMS messages and calls to. Inside the &lt;code&gt;main&lt;/code&gt; function add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun main(args: Array&amp;lt;String&amp;gt;) {
    System.setProperty("MY_NUMBER", System.getenv("MY_NUMBER"))
    SpringApplication.run(App::class.java, *args)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have my telephone number set as an &lt;a href="https://en.wikipedia.org/wiki/Environment_variable" rel="noopener noreferrer"&gt;environment variable&lt;/a&gt; on my computer. My colleague Dominik wrote a nice article explaining &lt;a href="https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html" rel="noopener noreferrer"&gt;how to set environment variables&lt;/a&gt; on Mac, Windows and Linux.&lt;/p&gt;

&lt;p&gt;Once you have the “MY_NUMBER variable set correctly for your environment with your own telephone number we’re ready to start building the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forwarding SMS messages
&lt;/h2&gt;

&lt;p&gt;We still want to get every SMS message sent to our burner phones, but we want them redirected to our own number. The beauty of doing this is that if we ever get tired of being spammed from a certain number, we can just discard that number on the Twilio console and be done with it.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;SMSController.kt&lt;/code&gt; and create a new mapping called &lt;code&gt;forwardSMS&lt;/code&gt; just below the one that is already there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.twilio.twiml.Body
import com.twilio.twiml.Message
import com.twilio.twiml.MessagingResponse
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RequestMapping("/sms")
@RestController class SMSController {
    @RequestMapping(value = "/")
    fun helloSpringBoot() = "A nice looking sms controller"

    @RequestMapping(value = "/forwardSMS", produces = arrayOf("text/xml"))
    fun forwardSMS(@RequestParam(value = "From") from: String, @RequestParam(value = "Body") body: String): String{
        val message = Message.Builder()
                .to(System.getProperty("MY_NUMBER"))
                .body(Body("Message from: $from \n $body")).build()
        return MessagingResponse.Builder().message(message).build().toXml()
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This new mapping will tell Twilio to forward any inbound SMS to our own number. It will forward the message so we still know whose number originally sent it.&lt;/p&gt;

&lt;p&gt;It is useful to know who sent the message so you can respond if you need or just as easily add a condition to the top of the mapping to block any messages from that specific sender.&lt;/p&gt;

&lt;p&gt;Restart the application and test it out by sending a &lt;code&gt;POST&lt;/code&gt; request to it with &lt;a href="https://curl.haxx.se/" rel="noopener noreferrer"&gt;cURL&lt;/a&gt; for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST 
  http://localhost:8080/sms/forwardSMS 
  -F From=+1234567890 
  -F 'Body=Checking my TwiML works'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the result should be the &lt;a href="https://www.twilio.com/docs/api/twiml" rel="noopener noreferrer"&gt;TwiML&lt;/a&gt; that will tell Twilio to forward the message.&lt;/p&gt;

&lt;p&gt;Before we configure our Twilio numbers let’s add call forwarding to our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forwarding Calls
&lt;/h2&gt;

&lt;p&gt;To forward calls we will use the same principle as above but will have it in a different controller to keep things neat. If you cloned the starter application you should already have that controller.&lt;/p&gt;

&lt;p&gt;Create a new Kotlin controller called &lt;code&gt;CallController.kt&lt;/code&gt; alongside &lt;code&gt;SMSController.kt&lt;/code&gt; if you don’t already have one.&lt;/p&gt;

&lt;p&gt;In that controller add the highlighted code or just copy everything if you still have an empty controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.twilio.twiml.*
import com.twilio.twiml.Number
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RequestMapping("/call")
@RestController class CallController {
    @RequestMapping(value = "/")
    fun helloSpringBoot() = "A nice looking call controller"

    @RequestMapping(value = "/forwardCall", produces = arrayOf("text/xml"))
    fun forwardCall(@RequestParam(value = "From") from: String): String{
        val call = Dial.Builder().number(Number.Builder(System.getProperty("MY_NUMBER")).build()).build()
        return VoiceResponse.Builder()
                .dial(call).say(Say.Builder("You have a call from $from").voice(Say.Voice.ALICE).build())
                .build().toXml()
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like before, we are adding information about the caller for when the call is forwarded. So when you get a call to this Twilio number you hear a message that tells you the number that is calling.&lt;/p&gt;

&lt;p&gt;You can also test that this is working correctly by making a POST request to it and checking that the &lt;a href="https://www.twilio.com/docs/api/twiml" rel="noopener noreferrer"&gt;TwiML&lt;/a&gt; returned looks right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2F9mv1RiAvhqGQ18XbZ9mTqU9EXnkx46MGg3kxZ9G8rnHblvAW7KKS9rhu_b7jyHzF4BLaow63BXeV9GZoJSOrgieiwnCynkQYjbyk0QrtVlkR62rNwNzeeQETNJZIb-bjKe5gZnds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2F9mv1RiAvhqGQ18XbZ9mTqU9EXnkx46MGg3kxZ9G8rnHblvAW7KKS9rhu_b7jyHzF4BLaow63BXeV9GZoJSOrgieiwnCynkQYjbyk0QrtVlkR62rNwNzeeQETNJZIb-bjKe5gZnds.png" alt="curl request to check for TwiML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we configure our Twilio numbers to use the application we need to deploy it somewhere. Let’s look at how to do this with &lt;a href="https://www.heroku.com/" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying your Kotlin application to Heroku
&lt;/h2&gt;

&lt;p&gt;If you haven’t yet create an account on Heroku. Once you have an account and installed the &lt;a href="https://devcenter.heroku.com/articles/heroku-cli" rel="noopener noreferrer"&gt;heroku toolbelt&lt;/a&gt;, go to your terminal and log in from there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heroku login
Enter your Heroku credentials.
Email: me@example.com
Password:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still in terminal create a new Heroku application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heroku create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you haven’t created this application from scratch but cloned the &lt;code&gt;starter-application&lt;/code&gt; repository, you will now need to merge it into master as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -am "complete tutorial"
git checkout master
git merge starter-application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can skip the step above if you created the project from scratch, just make sure you in master and we’re ready to push this to Heroku.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will take a few seconds and when it’s complete you should see a message that looks like this on your terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FNPbry1_yi4TU-__rUGzkTEWJj-tNodFdlopvlrnzKUfbll3fhvGJiG-l2966nyDb1-5ZTX9skrjQ4QFMUYzR_-kDjhdT-EnI9oD-73BbNC48S5S9yIEMYkmsTHbNFjrtJpkIt7uS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FNPbry1_yi4TU-__rUGzkTEWJj-tNodFdlopvlrnzKUfbll3fhvGJiG-l2966nyDb1-5ZTX9skrjQ4QFMUYzR_-kDjhdT-EnI9oD-73BbNC48S5S9yIEMYkmsTHbNFjrtJpkIt7uS.png" alt="creating a heroku application in Kotlin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this URL as we will use it later on to configure our Twilio numbers.&lt;br&gt;
Just like in our local environment we need to set a phone number as an environment variable for this deployment. You can do this by running the following on your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heroku config:set MY_NUMBER=+441234567890
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you use your own telephone number as the value for &lt;code&gt;MY_NUMBER&lt;/code&gt;. Now we’re ready to configure our burner numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating burner numbers
&lt;/h2&gt;

&lt;p&gt;The beauty of this application is that because we’re not hard-coding anything in the application itself, it can be used for as many Twilio numbers as we want. In our case, we could have one number for loyalty cards, one for prize draws and one for selling things on the internet.&lt;/p&gt;

&lt;p&gt;Head to the &lt;a href="https://www.twilio.com/console/phone-numbers/incoming" rel="noopener noreferrer"&gt;Twilio console&lt;/a&gt; and get as many numbers as you like, then configure and save them all as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FJiXCHuCdXGU4ZtcjAa3e1UuAT2f2AQB9ptBC8rCSpBTAPVqeZG2hNS51566XXhEerg7DffyKtw6MIlJlHwlTTiH7spCohyYRX000RbbM3WXuSYBAqIgkhX5HzwiNadr4vEPVlq5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FJiXCHuCdXGU4ZtcjAa3e1UuAT2f2AQB9ptBC8rCSpBTAPVqeZG2hNS51566XXhEerg7DffyKtw6MIlJlHwlTTiH7spCohyYRX000RbbM3WXuSYBAqIgkhX5HzwiNadr4vEPVlq5j.png" alt="Twilio console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure you change the application URL to match what you copied earlier when you deployed your application to Heroku.&lt;br&gt;
Give those numbers away instead of your own number now and just wait for all the messages and calls to start coming in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FE54orG-nolK-BzTAftsdIFK9ESQh38608oRoZ-HOgNME99AH8sJddfljQMoOro6BNkUVGUuwalXGli0ub2zQCgXHK9GgvUzNNaJddpT-u-RGdRJehvBa62lljM65iEfw99OBn8C.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FE54orG-nolK-BzTAftsdIFK9ESQh38608oRoZ-HOgNME99AH8sJddfljQMoOro6BNkUVGUuwalXGli0ub2zQCgXHK9GgvUzNNaJddpT-u-RGdRJehvBa62lljM65iEfw99OBn8C.png" alt="incoming messages to burner phone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Burn it!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FyIc_arxv5GJCxXWGqLO_1ruyfD48xh8Yo00m0RDw_0NQYEOoahehBDEzf1B76dH2hMwppC_zmww86Mkcocz_0S4WuqD5Rfase6d1yhb68fuYVl9hUCuY8oYnrT_RBjbRnYZZ70MJ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fblog%2Fwp-content%2Fuploads%2F2017%2F07%2FyIc_arxv5GJCxXWGqLO_1ruyfD48xh8Yo00m0RDw_0NQYEOoahehBDEzf1B76dH2hMwppC_zmww86Mkcocz_0S4WuqD5Rfase6d1yhb68fuYVl9hUCuY8oYnrT_RBjbRnYZZ70MJ.png" alt="gif of burning superhero"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having burner phones that can just be created and disposed of when they’re no longer needed has never been so easy.&lt;br&gt;
I personally have each one of my burner numbers added to my contacts so they display nicely when I get a call or text message and I know roughly what to expect.&lt;/p&gt;

&lt;p&gt;A nice addition to this application would be to add a way of blocking senders before messages or calls are forwarded to us, or adding a voicemail system for certain numbers to make sure we never miss any calls.&lt;/p&gt;

&lt;p&gt;I would love to see what new features you add to it. Hit me up on twitter &lt;a href="https://twitter.com/marcos_placona?lang=en" rel="noopener noreferrer"&gt;@marcos_placona&lt;/a&gt; or drop me a note on the comments below to tell me more about it.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.twilio.com/blog/2017/07/building-a-fully-featured-burner-phone-with-kotlin.html" rel="noopener noreferrer"&gt;Building a fully featured burner phone with Kotlin&lt;/a&gt; was originally published on the &lt;a href="https://www.twilio.com/blog" rel="noopener noreferrer"&gt;Twilio blog&lt;/a&gt; on July 12, 2017.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>twilio</category>
      <category>springboot</category>
      <category>burnerphone</category>
    </item>
    <item>
      <title>Get started with Android Things today!</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Mon, 19 Jun 2017 13:07:30 +0000</pubDate>
      <link>https://dev.to/mplacona/get-started-with-android-things-today</link>
      <guid>https://dev.to/mplacona/get-started-with-android-things-today</guid>
      <description>&lt;p&gt;Android Things is a very frictionless Android OS that helps developers build IoT applications using the Android framework and tools. You can read more about it on &lt;a href="https://androidthings.rocks/2017/01/01/what-really-is-android-things/" rel="noopener noreferrer"&gt;What really is Android Things&lt;/a&gt;. Let's have a look at how to get started with Android Things today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our tools
&lt;/h2&gt;

&lt;p&gt;The instructions described here have been tested on a Mac, but should be easily interchangeable with any other operating system.&lt;/p&gt;

&lt;p&gt;Android developers will already have most of the necessary tools to get started with Android Things, but here's what we will need. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/studio/index.html" rel="noopener noreferrer"&gt;Android Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A Raspberry Pi 3 - You can &lt;a href="http://amzn.to/2isZ6uN" rel="noopener noreferrer"&gt;get one here&lt;/a&gt; if you don't already have one lying around.&lt;/li&gt;
&lt;li&gt;A micro SD card with at least 8GB and an adapter so you can flash it. I have &lt;a href="http://amzn.to/2i0a4H9" rel="noopener noreferrer"&gt;this one&lt;/a&gt;, but anything will do.&lt;/li&gt;
&lt;li&gt;A copy of the &lt;a href="https://developer.android.com/things/preview/download.html" rel="noopener noreferrer"&gt;latest  Android things preview image&lt;/a&gt; for Raspberry Pi.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sdcard.org/downloads/formatter_4/" rel="noopener noreferrer"&gt;SD Card Formatter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;An ethernet cable connected to your router.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Flashing the image
&lt;/h2&gt;

&lt;p&gt;The Android Things website has instructions about &lt;a href="https://developer.android.com/things/hardware/raspberrypi.html#flashing_the_image" rel="noopener noreferrer"&gt;how to flash the image&lt;/a&gt;, but I found that buggy hard to follow so here's what I did.&lt;/p&gt;

&lt;p&gt;Open up the zip file you downloaded with Android things preview and there should be a file called &lt;code&gt;iot_rpi3.img&lt;/code&gt; inside of it. If you got the file, feel free to skip the next heading.&lt;/p&gt;

&lt;h3&gt;
  
  
  But I hit a snag!
&lt;/h3&gt;

&lt;p&gt;I hit a snag here where the extracted file was called &lt;code&gt;androidthings_rpi3_devpreview_4.zip.cpgz&lt;/code&gt;, and extracting that would give me a file called &lt;code&gt;androidthings_rpi3_devpreview_4 1.zip&lt;/code&gt; and this would go on pretty much forever. I found &lt;a href="http://osxdaily.com/2013/02/13/open-zip-cpgz-file/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; partially helpful.&lt;/p&gt;

&lt;p&gt;The gist of it is that you need to unzip the file via terminal, but using the methodology described on the website returned something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Archive:  androidthings_rpi3_devpreview_4.zip
warning &lt;span class="o"&gt;[&lt;/span&gt;androidthings_rpi3_devpreview_4.zip]:  76 extra bytes at beginning or within zipfile
  &lt;span class="o"&gt;(&lt;/span&gt;attempting to process anyway&lt;span class="o"&gt;)&lt;/span&gt;
error &lt;span class="o"&gt;[&lt;/span&gt;androidthings_rpi3_devpreview_4.zip]:  reported length of central directory is
  &lt;span class="nt"&gt;-76&lt;/span&gt; bytes too long &lt;span class="o"&gt;(&lt;/span&gt;Atari STZip zipfile?  J.H.Holm ZIPSPLIT 1.1
  zipfile?&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;  Compensating...
   skipping: iot_rpi3.img            need PK compat. v4.5 &lt;span class="o"&gt;(&lt;/span&gt;can &lt;span class="k"&gt;do &lt;/span&gt;v2.1&lt;span class="o"&gt;)&lt;/span&gt;

note:  didn&lt;span class="s1"&gt;'t find end-of-central-dir signature at end of central dir.
  (please check that you have transferred or created the zipfile in the
  appropriate BINARY mode and that you have compiled UnZip properly)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our file is in there as you can see, but just using the &lt;code&gt;unzip&lt;/code&gt; command does not extract it. 7zip was able to extract it though. You can install it by 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;brew &lt;span class="nb"&gt;install &lt;/span&gt;p7zip
&lt;span class="nv"&gt;$ &lt;/span&gt;7za x androidthings_rpi3_devpreview_4.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Formatting the memory card
&lt;/h3&gt;

&lt;p&gt;Insert the memory card on your Computer and you may get a message saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The disk you inserted was not readable by this computer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means this disk already had another image installed. Don't worry, just hit ignore. &lt;/p&gt;

&lt;p&gt;Open up SD Card Formatter, choose the SD Card and hit format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidthings.rocks%2Fimages%2FSDFormatter.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidthings.rocks%2Fimages%2FSDFormatter.png" alt="SD Card Formatter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your terminal run &lt;code&gt;diskutil&lt;/code&gt; and identify the disk number for your memory card.&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;diskutil list
/dev/disk2 &lt;span class="o"&gt;(&lt;/span&gt;external, physical&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;span class="c"&gt;#:                       TYPE NAME                    SIZE       IDENTIFIER&lt;/span&gt;
0:     FDisk_partition_scheme                        &lt;span class="k"&gt;*&lt;/span&gt;8.1 GB     disk2
1:                 DOS_FAT_32 NO NAME                 8.1 GB     disk2s1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unmount that disk:&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;diskutil unmountDisk /dev/disk2
Unmount of all volumes on disk2 was successful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're ready to flash the Android Things image to the disk. From the directory where your &lt;code&gt;*.img&lt;/code&gt; file is run:&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;&lt;span class="nb"&gt;sudo dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1m &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;iot_rpi3.img &lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/rdisk2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you change the value of &lt;code&gt;/dev/rdisk2&lt;/code&gt; to the number you got from when you run &lt;code&gt;diskutil list&lt;/code&gt;. So if you got &lt;code&gt;disk4&lt;/code&gt; for example, you should run the command above with &lt;code&gt;/dev/rdisk4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This can take some time, so go get yourself some coffee. You are flashing over 4GB into that SD card, and depending on it's speed this can take anywhere from 5 to 15 minutes.&lt;/p&gt;

&lt;p&gt;When the flashing is completed, your computer should give you the "The disk you inserted was not readable by this computer." message again. We're done with this bit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Booting up the image
&lt;/h3&gt;

&lt;p&gt;Get the memory card off your computer and insert it into the Raspberry Pi 3. I prefer to have it connected to a screen at this point as it gives me the confidence everything went ok.&lt;/p&gt;

&lt;p&gt;Connect the Pi's micro-usb to your computer and if you connected it to a screen you should see Android things booting up&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidthings.rocks%2Fimages%2Fandroid-things-boot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidthings.rocks%2Fimages%2Fandroid-things-boot.png" alt="Android Things first boot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great! But as you can see in the screen, we have no connectivity, which means we won't be able to get adb to connect to it. Thus making it impossible for us to upload our first application to our device. And this part of the documentation is not amazingly clear.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After flashing your board, it is strongly recommended to connect it to the internet. This allows your device to deliver crash reports and receive updates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But then I guess this is what the "I" in IoT means right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to the Internet
&lt;/h2&gt;

&lt;p&gt;Disconnect the Pi from your computer to power it down, and connect the ethernet cable on it. Now power it up again, and you should see that this time when it powers up it's assigned an IP Address.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidthings.rocks%2Fimages%2Fandroid-things-ethernet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidthings.rocks%2Fimages%2Fandroid-things-ethernet.png" alt="Android Things first boot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to your terminal an enter the following command:&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 connect Android.local
connected to Android.local:5555
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Android.local&lt;/code&gt; is automatically broadcast by the Raspberry Pi, and should resolve to the IP address assigned to your Pi on port 5555, so in our example the command above is the same as running &lt;code&gt;adb connect 192.168.0.23:5555&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;adb devices&lt;/code&gt; on your terminal should now list your Pi in the devices list. But having a cable always connected is a pain, so let's configure it to connect to our home WiFi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting to your WiFi
&lt;/h3&gt;

&lt;p&gt;Back in your terminal enter the following:&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 shell am startservice &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-n&lt;/span&gt; com.google.wifisetup/.WifiSetupService &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-a&lt;/span&gt; WifiSetupService.Connect &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; ssid &amp;lt;Network_SSID&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; passphrase &amp;lt;Network_Passcode&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you replace &lt;code&gt;&amp;lt;Network_SSID&amp;gt;&lt;/code&gt; with your network name and &lt;code&gt;&amp;lt;Network_Passcode&amp;gt;&lt;/code&gt; with your network's password. From &lt;a href="http://raspberrypi.stackexchange.com/a/43311" rel="noopener noreferrer"&gt;reading about the Raspberry Pi 3&lt;/a&gt;, it seems it's only able to connect to 2.4Ghz networks since it's only got one WiFi antenna.&lt;/p&gt;

&lt;p&gt;Running the command above will get your Pi connected to the WiFi. If you still have it up on the screen you will see that it gets an IP address assigned to it soon after you run it. You can now remove the ethernet cable from it. I found that restarting it again is best though as it guarantees the device is not &lt;code&gt;offline&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running your first Hello Things application
&lt;/h2&gt;

&lt;p&gt;This wouldn't be a complete tutorial if we didn't run an application to make sure Android was actually running on our Raspberry Pi as expected. You can continue following this through or just clone this application's repository &lt;a href="https://github.com/mplacona/HelloThings" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Android Studio, create a new project called &lt;code&gt;Hello Things&lt;/code&gt;. Android Things runs on API 24 and above, so make sure you pick Nougat or above and start that with an empty activity.&lt;/p&gt;

&lt;p&gt;Head to your application level Gradle file and add a dependency to Android Things.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;provided&lt;/span&gt; &lt;span class="s1"&gt;'com.google.android.things:androidthings:0.4-devpreview'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now head to the application's manifest and add an entry to the shared library and modify the intent filters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt;
    &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"@string/app_name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;uses-library&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.google.android.things"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MainActivity"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Launch activity as default from Android Studio --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.LAUNCHER"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Launch activity automatically on boot --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.IOT_LAUNCHER"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.DEFAULT"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, head to &lt;code&gt;hellothings/MainActivity.java&lt;/code&gt; and change the &lt;code&gt;onCreate&lt;/code&gt; method to list all the available peripherals on our Raspberry Pi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Bundle&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onCreate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;PeripheralManagerService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PeripheralManagerService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TAG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Available GPIO: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getGpioList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will return us with a list of every available General-purpose input/output (GPIO) in our Raspberry Pi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;01-02 19:40:52.589 1636-1636/rocks.androidthings.hellothings D/MainActivity: Available GPIO: [BCM12, BCM13, BCM16, BCM17, BCM18, BCM19, BCM20, BCM21, BCM22, BCM23, BCM24, BCM25, BCM26, BCM27, BCM4, BCM5, BCM6]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, if you still have your Pi connected to a screen, you will see that the activity called &lt;code&gt;Hello Things&lt;/code&gt; was started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidthings.rocks%2Fimages%2Fhello-things.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidthings.rocks%2Fimages%2Fhello-things.png" alt="Android Things application running"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now go ahead and play with some of the other samples on the &lt;a href="https://developer.android.com/things/sdk/samples.html" rel="noopener noreferrer"&gt;Android Things website&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>androidthings</category>
      <category>androiddev</category>
      <category>iot</category>
    </item>
    <item>
      <title>Certificate Pinning in Android</title>
      <dc:creator>Marcos Placona</dc:creator>
      <pubDate>Thu, 12 Jan 2017 17:46:45 +0000</pubDate>
      <link>https://dev.to/mplacona/certificate-pinning-in-android</link>
      <guid>https://dev.to/mplacona/certificate-pinning-in-android</guid>
      <description>&lt;p&gt;Certificate pinning is a security mechanism which allows HTTPS websites and applications using HTTPS services to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates.&lt;/p&gt;

&lt;p&gt;With certificate pinning it is possible to mitigate or severely reduce the effectiveness of &lt;a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack" rel="noopener noreferrer"&gt;MiTM&lt;/a&gt; attacks enabled by spoofing a back-end server's SSL certificate.&lt;/p&gt;

&lt;p&gt;If you are already using API's or services with &lt;a href="http://square.github.io/okhttp/" rel="noopener noreferrer"&gt;OkHTTP&lt;/a&gt; or any library that uses it, such as &lt;a href="https://square.github.io/retrofit/" rel="noopener noreferrer"&gt;Retrofit&lt;/a&gt; or &lt;a href="http://square.github.io/picasso/" rel="noopener noreferrer"&gt;Picasso&lt;/a&gt; the good news is that you're already half way there.&lt;/p&gt;

&lt;p&gt;Let's look at the following example from the &lt;a href="https://github.com/square/okhttp/wiki/Recipes#synchronous-get" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCall&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;enqueue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Callback&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onFailure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Call&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TAG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"onFailure: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Call&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;okhttp3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TAG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"onResponse: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you'd run it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;run("https://publicobject.com/helloworld.txt");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you think: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Great! I'm going though HTTPS, so this must be safe right?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well... No.&lt;/p&gt;

&lt;p&gt;With enough knowledge about proxies (N.B. I have barely just enough), one can intercept that request and see every incoming and outgoing packages... As plain text!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidsecurity.info%2Fimages%2F00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidsecurity.info%2Fimages%2F00.png" alt="00.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if we change our client slightly we can add certificate pinning to it, which will make it way harder for someone to impersonate our certificate and our app will refuse to make requests through that certificate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;CertificatePinner&lt;/span&gt; &lt;span class="n"&gt;certificatePinner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CertificatePinner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"publicobject.com"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sha256/0jQVmOH3u5mnMGhGRUCmMKELXOtO9q8i3xfrgq3SfzI"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;certificatePinner&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;certificatePinner&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;And your code will error and log a message like this.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;sh&lt;br&gt;
E/MainActivity: onFailure: Certificate pinning failure!&lt;br&gt;
                  Peer certificate chain:&lt;br&gt;
                    sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=: CN=publicobject.com,OU=PositiveSSL,OU=Domain Control Validated&lt;br&gt;
                    sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB&lt;br&gt;
                    sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB&lt;br&gt;
                  Pinned certificates for publicobject.com:&lt;br&gt;
                    sha256/0jQVmOH3u5mnMGhGRUCmMKELXOtO9q8i3xfrgq3SfzI=&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And this is &lt;strong&gt;great&lt;/strong&gt;! Because it tells us which &lt;a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm" rel="noopener noreferrer"&gt;SHA256&lt;/a&gt; hash we should be using. So now we can change our code to use the keys described on the error as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;java&lt;br&gt;
private CertificatePinner certificatePinner = new CertificatePinner.Builder()&lt;br&gt;
    .add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")&lt;br&gt;
    .add("publicobject.com", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=")&lt;br&gt;
    .add("publicobject.com", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=")&lt;br&gt;
    .build();&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And sure enough, if you run your code again everything should work as expected&lt;br&gt;
but with an added bonus. Our code is now checking that the certificate of the&lt;br&gt;
host matches with the one we're expecting. And if it doesn't, it will refuse to make a request.&lt;/p&gt;

&lt;p&gt;A proxy would then return a message saying: &lt;code&gt;No request was made. Possibly the SSL certificate was rejected.&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidsecurity.info%2Fimages%2F01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.androidsecurity.info%2Fimages%2F01.png" alt="01.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now we've pinned our certificate to our code.&lt;/p&gt;

</description>
      <category>android</category>
      <category>security</category>
      <category>androiddev</category>
      <category>ssl</category>
    </item>
  </channel>
</rss>
