<?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: Danilo Barreto</title>
    <description>The latest articles on DEV Community by Danilo Barreto (@dgbarreto).</description>
    <link>https://dev.to/dgbarreto</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F616095%2F76563b89-e1da-4ddd-a515-9189634bea08.jpeg</url>
      <title>DEV Community: Danilo Barreto</title>
      <link>https://dev.to/dgbarreto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dgbarreto"/>
    <language>en</language>
    <item>
      <title>The Koin Scope Bug That Teaches You What single vs. factory Actually Means</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Thu, 13 Aug 2026 23:34:24 +0000</pubDate>
      <link>https://dev.to/dgbarreto/the-koin-scope-bug-that-teaches-you-what-single-vs-factory-actually-means-3992</link>
      <guid>https://dev.to/dgbarreto/the-koin-scope-bug-that-teaches-you-what-single-vs-factory-actually-means-3992</guid>
      <description>&lt;h1&gt;
  
  
  The Koin Scope Bug That Teaches You What &lt;code&gt;single&lt;/code&gt; vs. &lt;code&gt;factory&lt;/code&gt; Actually Means
&lt;/h1&gt;

&lt;p&gt;Dependency injection frameworks make a promise: ask for a dependency, get an instance, don't worry about how it was constructed. Koin's &lt;code&gt;single {}&lt;/code&gt; and &lt;code&gt;factory {}&lt;/code&gt; definitions look interchangeable in a quick glance at the DI module — both are one-liners, both resolve the same type. They are not interchangeable, and building Finio produced a bug that makes the difference impossible to forget.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;AuthViewModel&lt;/code&gt; was originally registered in Koin as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;appModule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;factory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;AuthViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;factory {}&lt;/code&gt; means: every time something injects &lt;code&gt;AuthViewModel&lt;/code&gt;, Koin constructs a &lt;strong&gt;new instance&lt;/strong&gt;. That's fine for something stateless and cheap to build. It is not fine for a ViewModel holding observable auth state, because in Finio, &lt;code&gt;MainActivity&lt;/code&gt; injected &lt;code&gt;AuthViewModel&lt;/code&gt; directly (via &lt;code&gt;koinInject&lt;/code&gt;, to call &lt;code&gt;saveFcmToken&lt;/code&gt; after a successful login) while Compose screens injected their own &lt;code&gt;AuthViewModel&lt;/code&gt; through &lt;code&gt;by viewModel()&lt;/code&gt; for UI state observation.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;factory {}&lt;/code&gt;, those were &lt;strong&gt;two different objects&lt;/strong&gt;. &lt;code&gt;MainActivity&lt;/code&gt; held one instance of &lt;code&gt;AuthViewModel&lt;/code&gt;; the login screen's composable held another. When the login screen updated its instance's state (successful auth, user profile loaded), &lt;code&gt;MainActivity&lt;/code&gt;'s separate instance had no idea anything happened — it was still holding the old, unauthenticated state. Symptoms like "the FCM token doesn't get saved after login" or "the UI doesn't reflect the login I just did, depending on which part of the app checks state" trace directly back to this: two objects that look like one shared source of truth to the code reading them, but aren't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix, and why it's correct
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;appModule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;single&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;AuthViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;single {}&lt;/code&gt; means Koin constructs the instance once and returns that same instance for every subsequent injection request, for the lifetime of the Koin container. Now &lt;code&gt;MainActivity&lt;/code&gt; and every Compose screen injecting &lt;code&gt;AuthViewModel&lt;/code&gt; are looking at the same object. State mutated in one place is visible everywhere, which is the entire point of a ViewModel meant to represent shared session state.&lt;/p&gt;

&lt;h2&gt;
  
  
  When each one is actually correct
&lt;/h2&gt;

&lt;p&gt;The rule isn't "always use &lt;code&gt;single&lt;/code&gt;" — that would just trade one class of bug for a different one (unbounded memory retention, state leaking across contexts that shouldn't share it). The distinguishing question is: &lt;strong&gt;does this dependency represent shared state that multiple consumers need to observe consistently, or is it a stateless/cheap operation that's fine to reconstruct on demand?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;single {}&lt;/code&gt; fits shared, long-lived state: &lt;code&gt;AuthViewModel&lt;/code&gt; (session state), a database instance, a network client, anything acting as a source of truth that more than one part of the app reads or writes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;factory {}&lt;/code&gt; fits short-lived, stateless, or intentionally-isolated instances: a use case class with no internal state, a mapper, or a ViewModel that's genuinely scoped to one screen instance and shouldn't be shared even if injected from two places.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The open question this raised for the rest of the app
&lt;/h2&gt;

&lt;p&gt;Fixing &lt;code&gt;AuthViewModel&lt;/code&gt; surfaced a broader review that's still in progress in Finio: &lt;code&gt;TransactionViewModel&lt;/code&gt;, &lt;code&gt;BudgetViewModel&lt;/code&gt;, and &lt;code&gt;InsightsViewModel&lt;/code&gt; are currently all registered as &lt;code&gt;factory {}&lt;/code&gt;. Whether that's correct depends on the same question above, applied per-ViewModel, not assumed globally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a screen and, say, a widget or notification handler both need to observe the &lt;em&gt;same&lt;/em&gt; transaction list state, &lt;code&gt;factory {}&lt;/code&gt; will silently produce the same bug &lt;code&gt;AuthViewModel&lt;/code&gt; had — two instances, one seeing stale data.&lt;/li&gt;
&lt;li&gt;If each ViewModel is genuinely scoped to exactly one screen instance, with no other consumer expected to share its state, &lt;code&gt;factory {}&lt;/code&gt; is correct and arguably safer — it avoids holding a screen's state in memory after the screen itself is gone, and avoids one screen instance's data leaking into a re-visit of the same screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest answer, before "fix it" makes sense as an action: audit each ViewModel for whether it currently has, or is ever likely to have, more than one consumer that needs consistent shared state. &lt;code&gt;AuthViewModel&lt;/code&gt; failed that test because &lt;code&gt;MainActivity&lt;/code&gt; needed to observe/act on auth state outside the Compose tree that owned the "main" &lt;code&gt;AuthViewModel&lt;/code&gt; instance. &lt;code&gt;TransactionViewModel&lt;/code&gt; might genuinely not have that requirement yet — but "yet" is doing a lot of work in that sentence, and it's the kind of assumption worth writing down as a comment next to the Koin definition, not just carrying in your head.&lt;/p&gt;

&lt;h2&gt;
  
  
  The generalizable lesson
&lt;/h2&gt;

&lt;p&gt;Koin's &lt;code&gt;single&lt;/code&gt; vs. &lt;code&gt;factory&lt;/code&gt; distinction is really Koin's syntax for a much older DI concept — singleton scope vs. transient/prototype scope, present in Spring, Dagger, and virtually every DI framework under different names. The bug pattern this produces (two objects both believed to be "the" instance, one of them silently stale) isn't specific to Koin or even to Kotlin — it's what happens any time a DI container's scope configuration doesn't match the actual sharing requirements of the code consuming it. The fix is never "use single by default" or "use factory by default" — it's asking, for each registration, who else reads this, and do they need to see the same object I just mutated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;factory {}&lt;/code&gt; gives every injection a new instance; &lt;code&gt;single {}&lt;/code&gt; gives every injection the same instance. Treat this as a correctness decision, not a style preference.&lt;/li&gt;
&lt;li&gt;Any dependency injected from more than one place that needs to observe consistent state — a ViewModel read by both an Activity/Controller and a Compose/UI layer — almost always needs &lt;code&gt;single {}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When you find a &lt;code&gt;factory {}&lt;/code&gt;-scoped dependency injected in multiple places, that's the exact shape of bug to check for before assuming the issue is elsewhere in your state management.&lt;/li&gt;
&lt;li&gt;Audit DI scope decisions per-dependency, not as a blanket default — and write down &lt;em&gt;why&lt;/em&gt; a scope was chosen when it's not obvious, because "obviously scoped to one screen" today can quietly become "actually needs to be shared" after the next feature is added.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;This article is part of a series on the engineering decisions behind Finio, a Kotlin Multiplatform personal finance app. Full series and notes: &lt;a href="https://github.com/dgbarreto/tech-writing" rel="noopener noreferrer"&gt;github.com/dgbarreto/tech-writing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>androiddev</category>
      <category>dependencyinjection</category>
      <category>koin</category>
    </item>
    <item>
      <title>FCM Push Notifications and Deep Linking in Compose Multiplatform: The Payload Choice That Breaks Everything</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Sat, 08 Aug 2026 13:38:05 +0000</pubDate>
      <link>https://dev.to/dgbarreto/fcm-push-notifications-and-deep-linking-in-compose-multiplatform-the-payload-choice-that-breaks-jpl</link>
      <guid>https://dev.to/dgbarreto/fcm-push-notifications-and-deep-linking-in-compose-multiplatform-the-payload-choice-that-breaks-jpl</guid>
      <description>&lt;h1&gt;
  
  
  FCM Push Notifications and Deep Linking in Compose Multiplatform: The Payload Choice That Breaks Everything
&lt;/h1&gt;

&lt;p&gt;There's a single decision in Firebase Cloud Messaging that determines whether your Android push notification handling code runs at all when the app is backgrounded: whether you send a &lt;code&gt;notification&lt;/code&gt; payload or a &lt;code&gt;data&lt;/code&gt;-only payload. Get it wrong and your carefully written &lt;code&gt;onMessageReceived&lt;/code&gt; handler simply never fires — no crash, no error, just silence. This is one of the sharper lessons from building push notifications and deep linking for Finio, a Compose Multiplatform personal finance app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why data-only payloads are not optional
&lt;/h2&gt;

&lt;p&gt;FCM supports two payload shapes. A &lt;code&gt;notification&lt;/code&gt; payload is rendered by the OS notification tray automatically, which sounds convenient — until the app is backgrounded or killed, at which point Android intercepts it before it ever reaches your app's &lt;code&gt;onMessageReceived&lt;/code&gt; callback. Your &lt;code&gt;FinioMessagingService&lt;/code&gt; never runs, so any custom logic — routing data into the right screen, marking a budget alert as read, deep link payload construction — is skipped entirely.&lt;/p&gt;

&lt;p&gt;The fix is to always send &lt;strong&gt;data-only payloads&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"budget_alert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"budgetId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Budget Alert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"You've spent 90% of your Groceries budget"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a data-only payload, &lt;code&gt;onMessageReceived&lt;/code&gt; fires in every app state — foreground, background, or killed — and you take full responsibility for constructing the notification yourself, including navigating the intent when the user taps it. It's more code up front, but it's the only path that gives you control over what happens on tap, which is exactly what deep linking needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing the tap: &lt;code&gt;DeepLinkEventBus&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Once a push notification is tapped, the app needs to know it should open directly to a specific screen — in Finio's case, tapping a budget alert should land the user on the Budget tab, not the default home screen. The mechanism connecting "Android &lt;code&gt;Intent&lt;/code&gt; received in &lt;code&gt;MainActivity&lt;/code&gt;" to "Voyager navigator changes screen" is a &lt;code&gt;DeepLinkEventBus&lt;/code&gt;: a shared event stream that platform-specific entry points publish to, and that the Compose navigation layer subscribes to.&lt;/p&gt;

&lt;p&gt;The flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;FinioMessagingService.onMessageReceived&lt;/code&gt; builds a local &lt;code&gt;Notification&lt;/code&gt; from the data payload, attaching a &lt;code&gt;PendingIntent&lt;/code&gt; that carries the deep link target (e.g., &lt;code&gt;budgetId&lt;/code&gt; and a route identifier) as &lt;code&gt;Intent&lt;/code&gt; extras.&lt;/li&gt;
&lt;li&gt;When the user taps the notification, &lt;code&gt;MainActivity.onNewIntent&lt;/code&gt; (or &lt;code&gt;onCreate&lt;/code&gt;, if the app was killed) reads those extras and publishes an event onto &lt;code&gt;DeepLinkEventBus&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A composable observing the bus — typically hoisted near the root &lt;code&gt;Navigator&lt;/code&gt; — reacts to the event and calls into Voyager to push the Budget tab's screen onto the stack.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This indirection matters because &lt;code&gt;MainActivity&lt;/code&gt; shouldn't know about Voyager's navigation API directly, and the Compose navigation layer shouldn't know about Android's &lt;code&gt;Intent&lt;/code&gt; system. The event bus is the seam between "platform delivered a signal" and "UI reacted to it," which keeps the platform-specific code (&lt;code&gt;MainActivity&lt;/code&gt;, the &lt;code&gt;FinioMessagingService&lt;/code&gt;) decoupled from the shared Compose navigation logic — important in a KMP codebase where the iOS side needs the equivalent flow (APNs → deep link) to funnel into the &lt;em&gt;same&lt;/em&gt; shared navigation reaction, not a parallel implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  A rendering trap that looks unrelated but isn't
&lt;/h2&gt;

&lt;p&gt;One easy-to-miss detail on the Voyager side: a &lt;code&gt;Navigator&lt;/code&gt; composable requires calling &lt;code&gt;navigator.lastItem.Content()&lt;/code&gt; — not just referencing &lt;code&gt;navigator.lastItem&lt;/code&gt;. It's a one-token difference that fails silently: the screen state changes, the navigator's internal stack updates correctly, but nothing visibly renders, because &lt;code&gt;lastItem&lt;/code&gt; on its own is just a &lt;code&gt;Screen&lt;/code&gt; reference, not a call to its &lt;code&gt;Content&lt;/code&gt; composable. If a deep link event correctly updates navigation state but the UI doesn't visibly change, this is the first thing worth checking before assuming the event bus itself is broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug hiding in "why did I get this notification twice?"
&lt;/h2&gt;

&lt;p&gt;A concrete debugging example from Finio: the app was displaying two duplicate notifications on launch, even with no new pushes sent from the server. There are two candidate explanations worth separating before touching code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;FinioMessagingService&lt;/code&gt; itself firing twice for a single message (a service lifecycle or registration issue), or&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getBudgetWithProgress&lt;/code&gt; — the endpoint that evaluates whether a budget threshold was crossed — being called multiple times during initial load, each call independently deciding "this budget is over threshold, fire a notification."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These have different fixes. The first is a client-side FCM registration bug. The second is a backend logic gap: if budget alert evaluation happens as a side effect of a read endpoint, then anything that causes that endpoint to be called twice (a retry, a duplicate screen mount triggering the same ViewModel fetch, a race between cache and network) produces a duplicate alert, because there's no idempotency guard around "have I already alerted for this state."&lt;/p&gt;

&lt;p&gt;That second failure mode is really a design gap, not a bug: alert-firing is currently coupled to every evaluation of budget progress, with no memory of whether an alert was already sent. The options under consideration to fix this properly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;lastAlertSentAt&lt;/code&gt; with a 24-hour throttle&lt;/strong&gt; — simple, but can suppress a legitimate second alert if the user makes several large purchases in one day and crosses further thresholds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An &lt;code&gt;alertSent&lt;/code&gt; boolean that resets on budget renewal&lt;/strong&gt; — cleaner semantically (one alert per budget period), but requires the budget renewal job to explicitly reset the flag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fire only when the percentage crosses a threshold for the first time&lt;/strong&gt; — the most precise, but requires persisting the last-known percentage to detect a crossing rather than a static state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these is implemented yet in Finio; the point worth taking away isn't which one is "correct" in the abstract, but that duplicate-notification bugs are frequently a decoupling problem — a side effect (sending an alert) fired from something that has no concept of "have I done this already" (a stateless progress calculation) — rather than a duplicate-registration bug, and it's worth ruling out the simpler client-side explanation before redesigning the alert logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Always use data-only FCM payloads if you need custom logic to run in the background or killed app states — &lt;code&gt;notification&lt;/code&gt; payloads bypass your handler entirely outside the foreground.&lt;/li&gt;
&lt;li&gt;Keep an event bus (&lt;code&gt;DeepLinkEventBus&lt;/code&gt; or equivalent) as the seam between platform-specific intent handling and shared Compose navigation — it keeps both sides testable and keeps Android/iOS deep link entry points converging on one reaction path.&lt;/li&gt;
&lt;li&gt;With Voyager, remember &lt;code&gt;navigator.lastItem.Content()&lt;/code&gt;, not &lt;code&gt;navigator.lastItem&lt;/code&gt; — a common one-token bug that silently fails to render.&lt;/li&gt;
&lt;li&gt;When you see duplicate side effects (notifications, alerts, emails), check whether the side effect is coupled to a stateless read operation before assuming it's a registration or delivery bug — idempotency is usually the real fix.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;This article is part of a series on the engineering decisions behind Finio, a Kotlin Multiplatform personal finance app. Full series and notes: &lt;a href="https://github.com/dgbarreto/tech-writing" rel="noopener noreferrer"&gt;github.com/dgbarreto/tech-writing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>firebase</category>
      <category>kotlin</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Building a Design System That Actually Gets Used: Tokens, Components, and the AGP 9 Gotcha That Almost Broke It</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Tue, 21 Jul 2026 00:37:09 +0000</pubDate>
      <link>https://dev.to/dgbarreto/building-a-design-system-that-actually-gets-used-tokens-components-and-the-agp-9-gotcha-that-1hh1</link>
      <guid>https://dev.to/dgbarreto/building-a-design-system-that-actually-gets-used-tokens-components-and-the-agp-9-gotcha-that-1hh1</guid>
      <description>&lt;h1&gt;
  
  
  Building a Design System That Actually Gets Used: Tokens, Components, and the AGP 9 Gotcha That Almost Broke It
&lt;/h1&gt;

&lt;p&gt;A design system is only as good as its adoption rate. It's easy to publish a beautiful &lt;code&gt;FinioButton&lt;/code&gt; component and watch half the codebase quietly reach for raw &lt;code&gt;Material3&lt;/code&gt; &lt;code&gt;Button&lt;/code&gt; anyway because it was faster in the moment. The real engineering problem isn't drawing the components — it's making the design system the path of least resistance.&lt;/p&gt;

&lt;p&gt;Here's how &lt;code&gt;finio-design-system&lt;/code&gt;, one of five KMP libraries behind the Finio personal finance app, is structured to make that true, plus a packaging bug that silently strips your design system's resources out of production builds if you don't know to look for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tokens first, components second
&lt;/h2&gt;

&lt;p&gt;Everything in the design system is built on four token categories, each its own object in &lt;code&gt;dev.finio.designsystem.theme&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Colors&lt;/strong&gt; (&lt;code&gt;FinioColors.kt&lt;/code&gt;) — semantic, not literal. &lt;code&gt;primary = #6C63FF&lt;/code&gt;, but also purpose-built tokens like &lt;code&gt;success = #4CAF50&lt;/code&gt;, &lt;code&gt;error = #B00020&lt;/code&gt;, &lt;code&gt;subtle = #8A8AA8&lt;/code&gt;, &lt;code&gt;disabled&lt;/code&gt; / &lt;code&gt;onDisabled&lt;/code&gt; pairs. The naming convention pairs every "on-X" color with its background (&lt;code&gt;onPrimary&lt;/code&gt;, &lt;code&gt;onSurface&lt;/code&gt;, &lt;code&gt;onError&lt;/code&gt;), following the same pattern Material Design uses internally — which makes the token set easy to reason about even if you've never seen Finio's code before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spacing&lt;/strong&gt; (&lt;code&gt;FinioSpacing.kt&lt;/code&gt;) — a linear scale from &lt;code&gt;xxxs = 2.dp&lt;/code&gt; to &lt;code&gt;xxxl = 64.dp&lt;/code&gt;, in nine steps. Having nine named steps instead of arbitrary &lt;code&gt;dp&lt;/code&gt; values everywhere means a spacing audit is a search for raw &lt;code&gt;.dp&lt;/code&gt; literals, not a design review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Typography&lt;/strong&gt; (&lt;code&gt;FinioTypography.kt&lt;/code&gt;) — a full type scale from &lt;code&gt;displayLarge&lt;/code&gt; (57sp) down to &lt;code&gt;labelSmall&lt;/code&gt; (11sp), each with explicit &lt;code&gt;lineHeight&lt;/code&gt; and &lt;code&gt;letterSpacing&lt;/code&gt;, mirroring Material 3's type scale but scoped to the app's own object so it can diverge later without touching Material internals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shape&lt;/strong&gt; (&lt;code&gt;FinioShape.kt&lt;/code&gt;) — seven corner radius steps from &lt;code&gt;none&lt;/code&gt; to &lt;code&gt;full&lt;/code&gt; (a pill shape via &lt;code&gt;RoundedCornerShape(50)&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The rule enforced across the entire &lt;code&gt;finio-app&lt;/code&gt; codebase: &lt;strong&gt;no screen uses a hardcoded color, spacing, shape, or raw Material3 component.&lt;/strong&gt; Every value traces back to one of these four token objects, and every interactive element is a DS component (&lt;code&gt;FinioButton&lt;/code&gt;, &lt;code&gt;FinioTextField&lt;/code&gt;, &lt;code&gt;FinioCard&lt;/code&gt;) rather than &lt;code&gt;Button&lt;/code&gt;, &lt;code&gt;OutlinedTextField&lt;/code&gt;, or &lt;code&gt;Card&lt;/code&gt; directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing components around variants, not props explosion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;FinioButton&lt;/code&gt; is a useful example of API design under constraint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;FinioButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FinioButtonVariant&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FinioButtonVariant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FinioButtonVariant&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Secondary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Destructive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Ghost&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally, &lt;code&gt;FinioButton&lt;/code&gt; dispatches to &lt;code&gt;FinioPrimaryButton&lt;/code&gt;, &lt;code&gt;FinioSecondayButton&lt;/code&gt; (yes, that typo is load-bearing now — renaming it is a breaking API change for existing call sites, a reminder that public API surfaces accumulate small debts you choose to live with), &lt;code&gt;FinioDestructiveButton&lt;/code&gt;, and &lt;code&gt;FinioGhostButton&lt;/code&gt;. Each of those internal implementations pulls its colors, shape, and typography from tokens — &lt;code&gt;FinioColors.primary&lt;/code&gt; / &lt;code&gt;onPrimary&lt;/code&gt; for the primary variant, &lt;code&gt;FinioColors.error&lt;/code&gt; for destructive, &lt;code&gt;FinioShape.sm&lt;/code&gt;, &lt;code&gt;FinioTypography.labelLarge&lt;/code&gt; throughout.&lt;/p&gt;

&lt;p&gt;The pattern generalizes across the component set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FinioCardTransaction&lt;/code&gt; encodes an &lt;code&gt;enum class FinioTransactionType { Income, Expense }&lt;/code&gt; and maps it directly to &lt;code&gt;FinioColors.success&lt;/code&gt; / &lt;code&gt;FinioColors.error&lt;/code&gt; for the amount text — so "is this money coming in or going out" is a type-level decision, not a color chosen ad hoc at each call site.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FinioText&lt;/code&gt; ships as semantic wrappers (&lt;code&gt;FinioHeadline&lt;/code&gt;, &lt;code&gt;FinioBody&lt;/code&gt;, &lt;code&gt;FinioLabel&lt;/code&gt;) rather than exposing raw &lt;code&gt;Text(style = ...)&lt;/code&gt; calls, so a copy change to "what does body text look like app-wide" is one edit, not a find-and-replace across every screen.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FinioDialog&lt;/code&gt; bundles the interaction pattern itself (&lt;code&gt;isDestructive: Boolean&lt;/code&gt; swaps the confirm button to the &lt;code&gt;Destructive&lt;/code&gt; variant automatically) so a screen author can't accidentally ship a "delete this transaction" dialog with a primary-colored confirm button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread: the component API encodes the &lt;em&gt;decision&lt;/em&gt; (is this a destructive action? is this income or expense?), and the token/variant mapping happens once, inside the design system, instead of being re-derived by every screen that needs it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AGP 9 packaging bug that ships an app with no design system resources
&lt;/h2&gt;

&lt;p&gt;This is the kind of bug that doesn't show up until it's too late to catch in a code review: on AGP 9.x with &lt;code&gt;com.android.kotlin.multiplatform.library&lt;/code&gt;, Compose resources (&lt;code&gt;composeResources&lt;/code&gt;) are &lt;strong&gt;excluded from the published &lt;code&gt;.aar&lt;/code&gt; by default&lt;/strong&gt; unless you explicitly opt in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;androidLibrary&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;androidResources&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this line, &lt;code&gt;finio-design-system&lt;/code&gt; builds fine locally, publishes fine to GitHub Packages, and then throws &lt;code&gt;MissingResourceException&lt;/code&gt; at runtime in &lt;code&gt;finio-app&lt;/code&gt; — but only for whatever resources the design system bundles (icons, fonts) that got silently dropped from the artifact. It's a gap between "the library compiles" and "the library actually works when consumed," and it only surfaces once you try to run the consuming app, not when you build the library itself.&lt;/p&gt;

&lt;p&gt;If you're on AGP 9 with a KMP library module and you see resource-not-found exceptions that make no sense given the resource clearly exists in the source tree, check this flag first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making adoption the easy path, not the enforced path
&lt;/h2&gt;

&lt;p&gt;None of the token discipline above is enforced by a linter in Finio yet — it's a convention, reinforced by code review and by the fact that DS components are simply less code to write than reaching for Material3 directly and re-deriving colors and spacing by hand. That's a deliberate bet: a design system wins when using it correctly is less typing than not using it, not only when a CI check blocks the PR. The next step on the roadmap is exactly the enforcement layer — extracting &lt;code&gt;FinioNavigationBar&lt;/code&gt; as a standalone DS component instead of leaving it inlined in the app shell, and adding semantic income/expense color tokens to &lt;code&gt;FinioTheme&lt;/code&gt; to eliminate the last hardcoded &lt;code&gt;Color(0xFF2E7D32)&lt;/code&gt; / &lt;code&gt;Color(0xFFC62828)&lt;/code&gt; pair still living in &lt;code&gt;TransactionItem&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Build the token layer (color, spacing, typography, shape) before the component layer — components should consume tokens, never define values themselves.&lt;/li&gt;
&lt;li&gt;Encode decisions in the component API (destructive vs. primary, income vs. expense) rather than leaving color/style choices to whoever writes the screen.&lt;/li&gt;
&lt;li&gt;On AGP 9.x KMP library modules, explicitly enable &lt;code&gt;androidResources&lt;/code&gt; or your published artifact silently loses its bundled resources.&lt;/li&gt;
&lt;li&gt;Treat every hardcoded color or raw Material3 usage found in review as a design system gap to close, not a one-off exception to allow.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;This article is part of a series on the engineering decisions behind Finio, a Kotlin Multiplatform personal finance app. Full series and notes: &lt;a href="https://github.com/dgbarreto/tech-writing" rel="noopener noreferrer"&gt;github.com/dgbarreto/tech-writing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>androiddev</category>
      <category>compose</category>
      <category>designsystem</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Structuring a Kotlin Multiplatform App as a Library Ecosystem: Lessons from Building Finio</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:18:19 +0000</pubDate>
      <link>https://dev.to/dgbarreto/structuring-a-kotlin-multiplatform-app-as-a-library-ecosystem-lessons-from-building-finio-4f95</link>
      <guid>https://dev.to/dgbarreto/structuring-a-kotlin-multiplatform-app-as-a-library-ecosystem-lessons-from-building-finio-4f95</guid>
      <description>&lt;h1&gt;
  
  
  Structuring a Kotlin Multiplatform App as a Library Ecosystem: Lessons from Building Finio
&lt;/h1&gt;

&lt;p&gt;When most tutorials talk about Kotlin Multiplatform (KMP), they show you a single repo with a &lt;code&gt;shared&lt;/code&gt; module and call it a day. That works for a demo. It falls apart the moment you're building a real product with a backend team, a design system that needs to evolve independently, and features that ship on different cadences.&lt;/p&gt;

&lt;p&gt;While building &lt;strong&gt;Finio&lt;/strong&gt;, a personal finance app for Android and iOS, I split the codebase into six repositories instead of one monolith: a Node.js/TypeScript API, five independently published KMP library modules, and a Compose Multiplatform app shell that consumes all of them. Here's why, and what it actually takes to make that work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the ecosystem
&lt;/h2&gt;

&lt;p&gt;Finio is composed of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;finio-api&lt;/code&gt;&lt;/strong&gt; — a Node.js/TypeScript backend on Railway. Routes live inside feature modules (&lt;code&gt;src/modules/budget&lt;/code&gt;, &lt;code&gt;src/modules/transaction&lt;/code&gt;, etc.) rather than a separate &lt;code&gt;routes/&lt;/code&gt; folder, and request/response contracts are validated with Zod schemas in &lt;code&gt;src/schemas/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Five KMP library modules&lt;/strong&gt;, each published independently via Maven to GitHub Packages: &lt;code&gt;finio-design-system&lt;/code&gt;, &lt;code&gt;finio-auth&lt;/code&gt;, &lt;code&gt;finio-transaction&lt;/code&gt;, &lt;code&gt;finio-budget&lt;/code&gt;, &lt;code&gt;finio-insights&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;finio-app&lt;/code&gt;&lt;/strong&gt; — the Compose Multiplatform shell, split into &lt;code&gt;androidApp&lt;/code&gt;, &lt;code&gt;iosApp&lt;/code&gt;, &lt;code&gt;sharedLogic&lt;/code&gt;, and &lt;code&gt;sharedUI&lt;/code&gt;, which pulls in every library module as a dependency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app shell doesn't own business logic. It owns navigation, composition, and platform wiring (Koin DI graph, FCM registration, deep link handling). Everything else — auth flows, transaction parsing, budget calculations, insights — lives in a module that can be versioned, tested, and consumed on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why split it this way
&lt;/h2&gt;

&lt;p&gt;The obvious question: why not just use Gradle's multi-module setup inside one repo? Two reasons drove the decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Independent versioning.&lt;/strong&gt; When &lt;code&gt;finio-auth&lt;/code&gt; gets a bug fix, I don't want to force a new release of &lt;code&gt;finio-budget&lt;/code&gt; or touch anything in the app shell's build graph. Publishing each module as its own Maven artifact means &lt;code&gt;finio-app&lt;/code&gt;'s &lt;code&gt;build.gradle.kts&lt;/code&gt; just bumps a version string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dev.finio:auth:1.4.2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dev.finio:transaction:2.1.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Forcing a real API boundary.&lt;/strong&gt; When a module only exists as source inside a monorepo, it's tempting to reach across module boundaries "just this once." When a module is a compiled artifact pulled from GitHub Packages, that's not possible — you're forced to design a public API surface deliberately, the same discipline you'd apply to any external SDK.&lt;/p&gt;

&lt;p&gt;The tradeoff is real: cross-module changes now require publishing a new version and bumping it downstream, which is slower than editing a file in a monorepo. For a solo/small-team project this is a deliberate cost, taken on because it mirrors how larger organizations actually structure multiplatform codebases once more than one team touches the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;build.gradle.kts&lt;/code&gt; template that makes this repeatable
&lt;/h2&gt;

&lt;p&gt;Every KMP library module in Finio follows the same Gradle template, based on &lt;code&gt;finio-design-system&lt;/code&gt;. A few details matter more than they look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;localProperties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="c1"&gt;// read before the plugins block&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;publishVersion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kotlinMultiplatform&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// must come before androidMultiplatformLibrary&lt;/span&gt;
    &lt;span class="nf"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;androidMultiplatformLibrary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"maven-publish"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;androidLibrary&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;iosArm64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;iosSimulatorArm64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;iosArm64&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;iosSimulatorArm64&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;framework&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;baseName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"auth"&lt;/span&gt; &lt;span class="c1"&gt;// matches the internal module name — see below&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// publishing block lives OUTSIDE the kotlin { } block&lt;/span&gt;
&lt;span class="nf"&gt;publishing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;publications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MavenPublication&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;groupId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dev.finio"&lt;/span&gt;
        &lt;span class="n"&gt;artifactId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="c1"&gt;// pom { ... }&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;maven&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;credentials&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GITHUB_ACTOR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
                &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GITHUB_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two ordering rules aren't cosmetic: the &lt;code&gt;kotlinMultiplatform&lt;/code&gt; plugin has to be applied before &lt;code&gt;androidMultiplatformLibrary&lt;/code&gt;, and the &lt;code&gt;publishing&lt;/code&gt; block has to sit outside the &lt;code&gt;kotlin { }&lt;/code&gt; block. Get either wrong and you get Gradle configuration errors that don't obviously point back to ordering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The naming trap: internal module name vs. artifact ID
&lt;/h2&gt;

&lt;p&gt;The single most expensive lesson from this project: &lt;strong&gt;the internal module name determines the generated iOS framework/artifact ID&lt;/strong&gt;, and it has to match the domain, not be something generic like &lt;code&gt;shared&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Early on, &lt;code&gt;finio-auth&lt;/code&gt;'s internal module was named &lt;code&gt;shared&lt;/code&gt; — a leftover from scaffolding. That name propagated into the generated iOS artifact ID, producing a framework that didn't clearly correspond to what it was (auth), and colliding conceptually with any other module that also defaulted to &lt;code&gt;shared&lt;/code&gt;. The same issue showed up in &lt;code&gt;finio-transaction&lt;/code&gt;, where the Android artifact was published as &lt;code&gt;dev.finio:finio-transaction-android&lt;/code&gt; instead of the intended &lt;code&gt;dev.finio:transaction-android&lt;/code&gt; — traced back to the &lt;code&gt;artifactId&lt;/code&gt; assignment inside &lt;code&gt;withType&amp;lt;MavenPublication&amp;gt;&lt;/code&gt; not matching &lt;code&gt;project.name&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The fix in both cases was the same: rename the internal module to match its domain (&lt;code&gt;auth&lt;/code&gt;, &lt;code&gt;transactions&lt;/code&gt;) and verify the &lt;code&gt;artifactId&lt;/code&gt; block explicitly rather than relying on Gradle defaults. If you're setting up a similar structure, check this on day one — renaming a published artifact after consumers depend on it is a breaking change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves the app shell
&lt;/h2&gt;

&lt;p&gt;Because business logic lives in versioned libraries, &lt;code&gt;finio-app&lt;/code&gt; stays thin: Compose screens, Voyager navigation, Koin wiring, and platform-specific glue (push notification registration, deep link routing). Before wiring a new feature into the shell, the practice that's paid off is a &lt;strong&gt;DTO contract review&lt;/strong&gt; — checking that the fields a KMP module expects (e.g., &lt;code&gt;finio-transaction&lt;/code&gt;, &lt;code&gt;finio-budget&lt;/code&gt;) actually match what &lt;code&gt;finio-api&lt;/code&gt;'s Zod schemas return, before writing a single line of UI code against them. Contract mismatches caught at this stage are a diff; caught after UI is built, they're a rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;If you're structuring a KMP product for more than a weekend project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Treat each domain (auth, transactions, budget) as a library with a real public API, not a folder.&lt;/li&gt;
&lt;li&gt;Get the internal module naming right before you publish — it leaks into iOS artifact IDs and is expensive to rename later.&lt;/li&gt;
&lt;li&gt;Keep the &lt;code&gt;publishing&lt;/code&gt; block and plugin ordering consistent across every module via a shared template; copy-pasting Gradle config by hand invites drift.&lt;/li&gt;
&lt;li&gt;Validate backend/client contracts before building UI on top of them, not after.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this is exotic — it's the same modular discipline backend teams have applied to microservices for years, applied to a mobile codebase that happens to target two platforms from one Kotlin source tree.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article is part of a series on the engineering decisions behind Finio, a Kotlin Multiplatform personal finance app. Full series and notes: &lt;a href="https://github.com/dgbarreto/tech-writing" rel="noopener noreferrer"&gt;github.com/dgbarreto/tech-writing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kmp</category>
      <category>androiddev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Contratos no Kotlin</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Mon, 15 Jul 2024 20:49:24 +0000</pubDate>
      <link>https://dev.to/dgbarreto/contratos-no-kotlin-4k56</link>
      <guid>https://dev.to/dgbarreto/contratos-no-kotlin-4k56</guid>
      <description>&lt;p&gt;No desenvolvimento Android com Kotlin, um dos recursos avançados disponíveis para melhorar a segurança e a robustez do código são os "contracts". Contracts permitem que desenvolvedores definam condições que devem ser atendidas antes ou depois da execução de uma função. Este artigo explorará o conceito de contracts, sua importância, como utilizá-los e os benefícios que eles trazem para o desenvolvimento Android.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Que São Contracts?
&lt;/h2&gt;

&lt;p&gt;Contracts em Kotlin são declarações que definem condições para a execução de funções. Eles permitem que você especifique pré-condições e pós-condições que o compilador pode usar para otimizações e verificações de segurança. Isso ajuda a garantir que certas condições sejam verdadeiras em pontos específicos do código, melhorando a segurança em tempo de compilação e a legibilidade do código.&lt;/p&gt;

&lt;h2&gt;
  
  
  Importância dos Contracts
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Segurança em Tempo de Compilação&lt;br&gt;
Contracts permitem que o compilador faça verificações adicionais, ajudando a capturar erros mais cedo no ciclo de desenvolvimento.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Código Mais Claro e Direto&lt;br&gt;
Especificar pré-condições e pós-condições torna o código mais legível e documentado, facilitando o entendimento das expectativas de uma função.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Redução de Erros em Tempo de Execução&lt;br&gt;
Ao garantir que certas condições sejam atendidas antes de executar um bloco de código, você reduz a chance de erros em tempo de execução, como NullPointerException.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Exemplo de Uso de Contracts
&lt;/h2&gt;

&lt;p&gt;Vamos explorar um exemplo prático de como usar contracts em uma função Kotlin. Suponha que estamos desenvolvendo uma função de validação para um objeto Request.&lt;/p&gt;

&lt;p&gt;Definindo um Contract&lt;br&gt;
Aqui está um exemplo de função de validação que usa um contract para garantir que o objeto Request e seu argumento não sejam nulos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm61c0bv65wbd75tgwfaw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm61c0bv65wbd75tgwfaw.png" alt=" " width="800" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Explicação do Código
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Importação de Contracts:&lt;/strong&gt;&lt;br&gt;
O contrato é uma funcionalidade experimental no Kotlin, por isso é necessário importar o módulo kotlin.contracts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definição do Contract:&lt;/strong&gt;&lt;br&gt;
Dentro da função validate, usamos o bloco contract para definir as condições que devem ser verdadeiras para que a função retorne normalmente. Aqui, especificamos que a função só retorna (returns()) se request e request.arg não forem nulos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validação das Condições:&lt;/strong&gt;&lt;br&gt;
A seguir, realizamos verificações explícitas. Se request for nulo, lançamos uma exceção. Se request.arg for nulo ou vazio, também lançamos uma exceção.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefícios dos Contracts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Verificação Adiantada&lt;/strong&gt;&lt;br&gt;
Ao definir contratos, o compilador pode verificar essas condições durante a compilação, ajudando a identificar possíveis problemas mais cedo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Melhor Documentação do Código&lt;/strong&gt;&lt;br&gt;
O uso de contracts torna o código mais auto-documentado, esclarecendo quais condições são esperadas para a execução correta da função.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Maior Robustez&lt;/strong&gt;&lt;br&gt;
Garantir que pré-condições sejam atendidas antes da execução de um bloco de código reduz a possibilidade de falhas inesperadas durante a execução.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;O uso de contracts no desenvolvimento Android com Kotlin oferece uma maneira poderosa de definir e verificar condições críticas em seu código. Eles melhoram a segurança em tempo de compilação, tornam o código mais claro e reduzem a probabilidade de erros em tempo de execução. Implementar contracts em funções críticas pode aumentar significativamente a robustez e a qualidade geral do seu aplicativo. Como esse recurso ainda está em fase experimental, é importante acompanhar as atualizações da linguagem Kotlin para aproveitar ao máximo as melhorias e novidades futuras.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>android</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>O que há de novo no Android 13?</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Sat, 04 Jun 2022 13:48:55 +0000</pubDate>
      <link>https://dev.to/dgbarreto/o-que-ha-de-novo-no-android-13-l68</link>
      <guid>https://dev.to/dgbarreto/o-que-ha-de-novo-no-android-13-l68</guid>
      <description>&lt;p&gt;Chegou aquela hora feliz do ano em que temos uma versão nova do Android. Anunciado no Google I/O, o Android 13 tem uma séries de melhorias e mudanças que afeta não só a vida do usuário final, como a vida de nós desenvolvedores. Eu separei algumas das mudanças que afetam mais a vida do desenvolvedor até agora:&lt;/p&gt;

&lt;p&gt;Primeiro e principalmente, quando deve sair:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w5o72sbj8bb90ajmidv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w5o72sbj8bb90ajmidv.png" alt=" " width="789" height="180"&gt;&lt;/a&gt;&lt;br&gt;
Já podemos baixar e começar a adaptar os nossos recursos, para o release em Julho!&lt;/p&gt;

&lt;p&gt;E o que mais?&lt;/p&gt;

&lt;p&gt;1) JetPack Compose 1.2: O JetPack Compose traz uma série de ferramentas para ajudar a montar interfaces mais ricas e fluídas de forma mais simples. Ele traz nessa nova versão recursos como Downloadable Fonts, onde o sistema busca e baixa diretamente fontes do Google Fonts, ajudando a diminuir o tamanho final do apk. Outro recurso interessantes é o Lazy Grid, permitindo montar grids de objetos em tamanho diferentes e não padronizados com menos linhas de código.&lt;/p&gt;

&lt;p&gt;2) Melhorias no Android Studio: com o lançamento do AS Dolphin e o Eletric Eel em Canary, temos um monte de recursos novos chegando.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LogCatV2: LogCat remodelado, ajudando na visualização, busca e filtro de registros&lt;/li&gt;
&lt;li&gt;Gradle Managed Devices: tudo o que você precisa fazer é descrever o device que precisa pra rodar os seus testes e o GMD cuida do resto pra você! Ele baixa o SDK, provisiona, executa os testes, desmonta o ambiente. &lt;/li&gt;
&lt;li&gt;Live Edit: todo o código que você altera, visualmente no Compose, pode ser visto em tempo real, não só na tela de preview como também no emulador e no device físico!&lt;/li&gt;
&lt;li&gt;Baseline Profiles: ele permite que apps e bibliotecas adicionem metadados em vistas a ajudar o compilador ahead-of-time a priorizar certos caminhos de código em vistas a deixar a experiência inicial do usuário mais rápida. Essa técnica já está sendo usada em libs como Fragments e Compose e também no app da Play Store, que já reportou ganho de velocidade de 40%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3) Outras melhorias gerais como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Privacy Sandbox: um novo conjunto de APIs, ainda em preview, para disponibilização de conteúdo para o usuário de forma mais fácil e sem conflitar com as suas preferências de privacidade&lt;/li&gt;
&lt;li&gt;Google Wallet: o Google Pay Passes está integrando ao serviço de pagamentos agora chamado Google Wallet. A nova API agora permite a gravação de passes genéricos e o agrupamento em vouchers&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>jetpack</category>
      <category>mobiledevelopment</category>
    </item>
    <item>
      <title>Opcionais no Swift</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Fri, 17 Dec 2021 17:54:43 +0000</pubDate>
      <link>https://dev.to/dgbarreto/opcionais-no-swift-1c0o</link>
      <guid>https://dev.to/dgbarreto/opcionais-no-swift-1c0o</guid>
      <description>&lt;p&gt;Você já viu um monte de códigos no Swift com "?" e "!" e fica perdido? Usa esses operadores mas sem saber direito quando e onde usar? Esse post então é pra você. &lt;/p&gt;

&lt;h2&gt;
  
  
  O que é um "?" no Swift
&lt;/h2&gt;

&lt;p&gt;O símbolo "?" representa um opcional no Swift. E um opcional é (pasmem) um &lt;strong&gt;enum&lt;/strong&gt;: .Some(Valor Encapsulado) e .None. Isso permite que ele possa ser vazio (.None) ou possa ter algum valor internamente (.Some(valor).&lt;/p&gt;

&lt;p&gt;Exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao criar uma variável com "?", no caso &lt;strong&gt;Int?&lt;/strong&gt; o Swift cria um enum do tipo &lt;strong&gt;Optional&lt;/strong&gt; mas com o estado &lt;strong&gt;.Some(10)&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso contrário, se você atribui &lt;em&gt;nil&lt;/em&gt;, é criada uma variável do tipo &lt;strong&gt;Optional&lt;/strong&gt; com o estado &lt;strong&gt;.None&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparação
&lt;/h2&gt;

&lt;p&gt;Sabendo agora como é armazenado um &lt;em&gt;Opcional&lt;/em&gt;, o Swift oferece algumas formas de trabalhar com ele. Podemos comparar ele de algumas formas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Valor de x &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;None&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"x não tem valor"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uma boa prática é "desembrulhar" (do inglês unwrap) o valor da váriavel de forma segura usando o guard. O guard pode ser executado da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?){&lt;/span&gt;
   &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Encadeamento Opcional
&lt;/h2&gt;

&lt;p&gt;O encadeamento opcional permite você pegar o valor de dentro de um opcional. Diferente do Unwrapping Forçado que vou falar a seguir, ele não causa um erro caso não tenha um valor dento do Opcional. Vamos ao exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;// .Some(10)&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo simples acima quando eu chamo &lt;strong&gt;x?&lt;/strong&gt; eu faço um unwrapping do Opcional, ou seja, eu pego somente o valor que existe dentro dele. Vamos para um exemplo um pouco mais complexo. Considere o código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;residence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Residence&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Residence&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;numberOfRooms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora considere a seguinte função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;john&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;roomCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;john&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;residence&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numberOfRooms&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Número de quartos &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;roomCount&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Não foi possível determinar o número de quartos"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O trecho de código acima não irá produzir um erro, pois o encadeamento opcional sempre retornar um Opcional que pode ser comparado. Mas ele será &lt;em&gt;nil&lt;/em&gt;. Então sua condição irá cair no &lt;em&gt;else&lt;/em&gt;. Mas se mudarmos aqui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;john&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="n"&gt;john&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;residence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Residence&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;roomCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;john&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;residence&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numberOfRooms&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Número de quartos &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;roomCount&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Não foi possível determinar o número de quartos"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O retorno será &lt;strong&gt;1&lt;/strong&gt;, pois é o valor padrão da quantidade de quartos. &lt;/p&gt;

&lt;h2&gt;
  
  
  Unwrapping Forçado
&lt;/h2&gt;

&lt;p&gt;O unwrapping forçado tem uma sintaxe parecida, trocando apenas "?" por "!". Mas ele tem uma diferença fundamental: Caso o valor no Opcional seja &lt;em&gt;nil&lt;/em&gt;, é gera um erro de execução e o aplicativo irá encerrar, caso não tratado. Utilizando o exemplo acima:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;john&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;roomCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;john&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;residence&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="n"&gt;numberOfRooms&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//o app irá quebrar nessa linha&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Número de quartos &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;roomCount&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Não foi possível determinar o número de quartos"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o unwrapping forçado só deve ser usado caso você tenha ABSOLUTA CERTEZA de que o Opcional tenha valor. &lt;/p&gt;

&lt;h2&gt;
  
  
  Coalescência
&lt;/h2&gt;

&lt;p&gt;O operador de coalescência "??" permite que você retorne o primeiro valor não nulo (nil) de duas variáveis. Vamos deixar mais claro no exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="c1"&gt;//o valor de e será 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo acima prevalece o primeiro valor não nil. Segundo exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="c1"&gt;//o valor de e será 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como no exemplo acima c é nil, o valor de e será 5, o primeiro valor não nil.&lt;/p&gt;

&lt;h2&gt;
  
  
  BONUS ADVANCED: Map e FlatMap
&lt;/h2&gt;

&lt;p&gt;O tipo Opcional ainda oferece duas funções chamadas Map e Flatmap que permitem que você controle o método de unwrapping passando um closure. A única diferença entro o Map e Flatmap é que o Map não pode devolver nil. Exemplos, exemplos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;z&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;FlatMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É isso gente. Esse é todo o "mistério" dos Opcionais no Swift. A partir de agora você já sabe ler quando encontrar "?" e "!" nos códigos e sabe como posicionar nos seus próprios códigos.&lt;/p&gt;

&lt;p&gt;Até a próxima! Keep coding!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Nativo x Hibrido?</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Sat, 27 Nov 2021 20:42:20 +0000</pubDate>
      <link>https://dev.to/dgbarreto/nativo-x-hibrido-13g6</link>
      <guid>https://dev.to/dgbarreto/nativo-x-hibrido-13g6</guid>
      <description>&lt;p&gt;No desenvolvimento mobile nos dias de hoje temos diversas opções para criar um app. As pessoas me procuram sempre com essa dúvida: o que usar? E eu sempre respondo: depende!&lt;/p&gt;

&lt;p&gt;Não existe uma fórmula mágica que determine qual estratégia usar, mas eu reunião neste paper os principais pontos para essa tomada de decisão. A principal tomada de decisão, na minha visão, é se devemos seguir com o desenvolvimento nativo ou híbrido.&lt;/p&gt;

&lt;p&gt;Dentro do desenvolvimento híbrido, é claro, temos muitas vertentes, mas estou considerando por hora Flutter e React Native. Mas a decisão crucial ainda repousa entre o nativo x híbrido. As variações de equipe, custo, qualidade são enormes! &lt;/p&gt;

&lt;p&gt;Pode baixar o paper &lt;a href="https://1drv.ms/b/s!AhUytFEWx6jHg5YSVTqMFSD-TthOlA?e=Oj7QXH" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>nativo</category>
      <category>hibrido</category>
    </item>
    <item>
      <title>Injeção de Dependência</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Tue, 16 Nov 2021 16:48:41 +0000</pubDate>
      <link>https://dev.to/dgbarreto/injecao-de-dependencia-5ap7</link>
      <guid>https://dev.to/dgbarreto/injecao-de-dependencia-5ap7</guid>
      <description>&lt;p&gt;O que é injeção de dependência? O que ela tem a ver comigo? O que ela come?&lt;/p&gt;

&lt;p&gt;A injeção de dependência é uma prática essencial nos dias de hoje. Apesar de eu falar sobre ela no âmbito do Android, ela é utilizada em todas as linguagens orientadas a objeto, pois ela fornece um fraco acoplamento entre as entidades, permitindo que a sua aplicação possua uma boa arquitetura. Ela também possui um papel fundamental nos testes automatizados, pois permite quer façamos a troca das dependências sem realizar nenhuma modificação nas classes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Vamos de exemplo
&lt;/h1&gt;

&lt;p&gt;Imagine um carro. O carro possui uma dependência de um motor. Nós podemos representar dessa forma no Kotlin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;engine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso o motor está definido dentro do carro. Temos um acoplamento forte, pois o carro só permite um tipo de motor. Essa relação cria uma dificuldade caso eu queira um motor diferente. Nos testes automatizados, caso eu queira criar um FakeMotor() isso também não seria possível. &lt;br&gt;
Mas com uma alteração já podemos ver algo diferente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui já podemos dizer que temos uma injeção de dependência! Quando recebemos o Engine como parâmetro permitimos diferentes implementações como um EletricMotor ou um FakeMotor no caso de um teste automático. A forma demostrada acima é chamada de &lt;strong&gt;Injeção de Construtor&lt;/strong&gt;. No Android podemos fazer de outra forma com Kotlin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;car {

   lateinit var engine: &lt;/span&gt;&lt;span class="nc"&gt;Engine&lt;/span&gt;

   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;car&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa segunda forma é chamada se &lt;strong&gt;Injeção de Setter&lt;/strong&gt;. Como Algumas classes são instanciadas por sistema, como Activities ou Fragments, as vezes não é possível se utilizar da Injeção por Construtor.&lt;/p&gt;

&lt;p&gt;Essa é a forma manual de injeção de dependência. Agora imagine que você precisa instanciar todas a partes de um carro? Muita coisa né? Pra isso existem bibliotecas como o Dagger ou o Hilt que podem ajudar a fazer isso de forma automática criando um Graph em memória. Mas isso é assunto para um próximo artigo. A lição valiosa importante aqui é gerar um acoplamento forte da sua classe, pois isso engessa o seu modelo e torna qualquer teste e qualquer refatoração um trabalhão no futuro!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Nova ferramenta do Facebook para encontrar falhas de segurança em apps Android</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Fri, 08 Oct 2021 20:43:00 +0000</pubDate>
      <link>https://dev.to/dgbarreto/nova-ferramenta-do-facebook-para-encontrar-falhas-de-seguranca-em-apps-android-4kia</link>
      <guid>https://dev.to/dgbarreto/nova-ferramenta-do-facebook-para-encontrar-falhas-de-seguranca-em-apps-android-4kia</guid>
      <description>&lt;p&gt;Há alguns dias o Facebook liberou para o público uma ferramenta, até então caseira, para descobrir falhas de segurança e privacidade em aplicações Anndroid e Java. &lt;/p&gt;

&lt;p&gt;Batizada de Mariana Trench (MT) e distribuida de forma Open Source a ferramenta está em constante evolução e suporte pelo time de engenharia do Facebook. Ela é usada hoje em milhões de linhas de código no Whatsapp, Instagram e, claro, no próprio app do Facebook. Segundo o Facebook, na primeira metade de 2021, 50% das vulnerabilidades encontradas foram de forma automatizada.&lt;/p&gt;

&lt;p&gt;O MT foi desenvolvido em Python e roda de forma estática no código. Está disponível (aqui)[&lt;a href="https://github.com/facebook/mariana-trench/" rel="noopener noreferrer"&gt;https://github.com/facebook/mariana-trench/&lt;/a&gt;). O Facebook também deixou pronto um tutorial para facilitar nos primeiros passos. O tutorial pode ser acessado (aqui)[&lt;a href="https://mariana-tren.ch/docs/getting-started/" rel="noopener noreferrer"&gt;https://mariana-tren.ch/docs/getting-started/&lt;/a&gt;].&lt;/p&gt;

</description>
      <category>android</category>
      <category>facebook</category>
      <category>security</category>
    </item>
    <item>
      <title>Face Detection com Android e Kotlin</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Thu, 23 Sep 2021 18:37:10 +0000</pubDate>
      <link>https://dev.to/dgbarreto/face-detection-com-android-e-kotlin-3i86</link>
      <guid>https://dev.to/dgbarreto/face-detection-com-android-e-kotlin-3i86</guid>
      <description>&lt;p&gt;O Google disponibiliza uma API que permite realizar detecção de rostos de maneira offline, sem depender de nenhum serviço na nuvem. Essa API é a Google Vision e foi introduzida no Play Services na versão 8.1. Fazer uma implementação básica é bem simples:&lt;/p&gt;

&lt;p&gt;Inclua a referência no build.gradle:&lt;br&gt;
&lt;code&gt;implementation 'com.google.android.gms:play-services-vision:8.1.0'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Em seguida vem a implementação do controle&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.avanade.myfacedetection&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.content.Context&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.graphics.*&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.util.AttributeSet&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.util.SparseArray&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.View&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;androidx.core.util.valueIterator&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.android.gms.vision.Frame&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.android.gms.vision.face.Face&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.android.gms.vision.face.FaceDetector&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FaceOverlayView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AttributeSet&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defStyleAttr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defStyleAttr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AttributeSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;mBitmap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bitmap&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;mFaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SparseArray&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Face&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SparseArray&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Face&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bitmap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bitmap&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;mBitmap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bitmap&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;faceDetector&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FaceDetector&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FaceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTrackingEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLandmarkType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FaceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ALL_LANDMARKS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FaceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ACCURATE_MODE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;faceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOperational&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
            &lt;span class="c1"&gt;//TODO: Colocar verificação&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;frame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Frame&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mBitmap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;mFaces&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;faceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;faceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onDraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mBitmap&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;mFaces&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;scale&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;drawBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
                &lt;span class="nf"&gt;drawFaceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;drawBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;viewWidth&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;viewHeight&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;imageWidth&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mBitmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;imageHeight&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mBitmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;scale&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewWidth&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;imageWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;viewHeight&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;imageHeight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;bounds&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Rect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageWidth&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageHeight&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mBitmap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;drawFaceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Paint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Paint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BLUE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Paint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STROKE&lt;/span&gt;
        &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strokeWidth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;5F&lt;/span&gt;

        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;left&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0F&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;top&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0F&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;right&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0F&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;bottom&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0F&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;face&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mFaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valueIterator&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
            &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;
            &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;
            &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui fazemos a criação do objeto que faz a detecção dos rostos na foto&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;faceDetector&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FaceDetector&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FaceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTrackingEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLandmarkType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FaceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ALL_LANDMARKS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FaceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ACCURATE_MODE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logo abaixo temos &lt;code&gt;if(!faceDetector.isOperational())&lt;/code&gt; que é uma verificação importante. Caso o usuário nunca tenha usado em nenhuma aplicação a API do Google Vision o device vai baixar essa lib e, pode ser que nesse momento a API ainda não esteja disponível. Então é importante fazer essa verificação para evitar um erro de NullPointerException.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;frame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Frame&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setBitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mBitmap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;mFaces&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;faceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;faceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui é onde o código irá efetivamente analisar a imagem e verificar os rostos das pessoas. As informações dos rostos encontrados é armazenado em um array de Faces usado aqui para desenhar os quadrados sobre o frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;face&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mFaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valueIterator&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
            &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;
            &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;
            &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código completo está aqui no &lt;a href="https://github.com/dgbarreto/facedetectionandroidkotlin" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Aqui também está um vídeo da implementação:&lt;br&gt;
&lt;a href="http://www.youtube.com/watch?feature=player_embedded&amp;amp;v=YlA1X6zcw_8" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fimg.youtube.com%2Fvi%2FYlA1X6zcw_8%2F0.jpg" alt="Face Detection com Android e Kotlin" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>androidstudio</category>
      <category>facedetection</category>
    </item>
    <item>
      <title>Mudança de Privacidade Chegando</title>
      <dc:creator>Danilo Barreto</dc:creator>
      <pubDate>Wed, 22 Sep 2021 12:41:52 +0000</pubDate>
      <link>https://dev.to/dgbarreto/mudanca-de-privacidade-chegando-k0g</link>
      <guid>https://dev.to/dgbarreto/mudanca-de-privacidade-chegando-k0g</guid>
      <description>&lt;p&gt;O Google estará liberando nos próximos meses uma melhoria nos recursos de privacidade. Esse recurso terá como algo todas aquelas aplicações mais antigas, esquecidas e sem uso, que possuam acesso a dados sensíveis.&lt;br&gt;
Entre os recursos que serão "perdidos" para essas apps estão envio de SMS, sensores e acesso à lista de contatos.&lt;br&gt;
"O recurso será habilitade por padrão em apps rodando Android 11 (API level 30) ou superior. Contudo, usuários poderão habilitar auto-reset de permissões para apps rodando com API levels 23 a 29", disse o Google.&lt;/p&gt;

&lt;p&gt;Esse novo recurso visa aumentar ainda mais a segurança digital, prevenindo que apps antigas possam se aproveitar desses acessos concedidos e, com alguma atualização, rodar algum código malicioso ou abrir portas para tal. &lt;/p&gt;

&lt;p&gt;A atualização deve começar a sair para o público geral a partir de Dezembro, mas deve demorar até o final de Março/2022 para atingir todo o público esperado.&lt;/p&gt;

</description>
      <category>android</category>
      <category>security</category>
      <category>news</category>
    </item>
  </channel>
</rss>
