Run Custom Gradle Task After “build”

After running ./gradlew build on my Kotlin Multiplatform project, I wanted to copy the JavaScript build artifacts (.js & .html) to publish a demo where someone could test my library via a web browser. A custom Gradle task is is a great way to write your own behavior to accomplish this using the Gradle build system.

My Custom Gradle Task

I found the Gradle documentation for how to copy files, and was able to write this custom task "myTaskName" to do it. You can then just run ./gradlew myTaskName and it’ll run the task independently. The problem was that I didn’t know how to get it to always run after ./gradlew build ran.

/** Copies files from "build/distributions" to "demo" directory */
tasks.register<Copy>("myTaskName") {
    println("Copying Build Artifacts!!!")
    from(layout.buildDirectory.dir("distributions"))
    include("**/*.*")
    into(layout.buildDirectory.dir("../demo"))
}

TL;DR – Use finalizedBy()

  • finalizedBy – Runs my task AFTER “build”. ✅
    • tasks.named("build") { finalizedBy("myTaskName") }
  • dependsOn – Runs “build” BEFORE my task, if my task is executed explicitly.
    • tasks.named("myTaskName") { dependsOn("build") }

To give you more details and to go into my process of how I figured it out, here are a few options I tried while figuring out how to run this custom task after every execution of the “build” Gradle task.

1. finalizedBy ✅

You can use finalizedBy() to say what task you should run after a named task. I think this reads nicely because it calls out the task dependency separately from it’s declaration. This will appropriately run after the build task executes as I needed.

tasks.named("build") { finalizedBy("myTaskName") }

2. shouldRunAfter 🤔

Another possible way to do this is with shouldRunAfter() which can just be added inside the block where you register your custom task. This will run after the build task executes. HOWEVER: I had to call .get() after registering my task to get it to work in order to have this actually run, which just feels wrong… Someone feel free to explain why, but I’m guessing this is some sort of lazy initialization happening if I don’t call “.get()”. Because of this, I don’t like this solution personally.

tasks.register<Copy>("myTaskName") {
    shouldRunAfter("build") // Tells Gradle to execute after "build" task
    // My Custom Task Code
}.get()

3. dependsOn() 🙃

You would think dependsOn() may work, but it’s the opposite behavior than what I wanted. It’s saying that “myTaskName” needs “build” to have run before it executes. It’s the opposite task dependency relationship from finalizedBy(). This wasn’t the behavior I wanted for this use case because I wanted it to copy the artifacts after every time a ./gradlew build was run, but could be useful depending on your use case.

tasks.named("myTaskName") { dependsOn("build") }

Wrap Up

None of this is rocket science, but if you try to Google for how to do it, it may take you a while to figure out how to do it. Using Option 1, finalizedBy() was the solution that worked for my use case! I hope this saved you an hour or more!

Intro to Kotlin Multiplatform JavaScript

One of the compilation targets of Kotlin Multiplatform is JavaScript. It’s pretty awesome that I can take the same Kotlin code and tools I write Android with, and write code that runs in a browser (or in Node.js).

Here is the video I’ve created to walk you through the creation of a Kotlin Multiplatform Project using the templates in Intellij IDEA, and what you can do to get your Kotlin running as JavaScript in the Browser!

Here are the code snippets mentioned in the video:

./gradlew build
 js(LEGACY) {
     browser {
         webpackTask {
             output.libraryTarget = "this" // Will add to window
         }
         binaries.executable()
     }
 }
 fun printHi() {
     println("Hello World Sam!")
 }
 fun main(args: Array) {
     printHi()
 }
 helloworldsam.printHi()

What & Why, Not How

As engineers we love to dive into problems and start thinking of how we can use the latest frameworks and architecture patterns to solve a problem, but we don’t always spend as much time thinking about what problem we are solving and why.

Engineers focus on “how” we should build something.

We build amazing solutions to really hard problems. Yes, our implementations will probably go through many iterations, but will end up as an elegant solution in the end. The ability to bring hard technical problems to fruition is an invaluable skill.

Engineering Mindset ➡ Leadership Mindset

Leadership and prioritization are hard, and they require you to take off your engineering hat. The way to do that, is to step away from thinking about how you are going to solve something.

Stereotypically, leaders are thought of as people that just focus on business goals and don’t worry about the technical problems. While this might be true in some cases, there are great engineering leaders who are aware of the technical landscape and can balance business and technology.

Exercise: List out what you want to and why without taking how into consideration.

Because switching context is really hard, do this exercise early in the morning when your thoughts are fresh and you haven’t dug into any code yet for the day.

Create a two columns with WHAT & WHY, and don’t allow yourself to enumerate on HOW. List out all the things you want to focus on.

Done? Okay, what did you come up with?

Did upgrading to the latest version of a library really end up being a top priority? If so, you have probably justified why. Maybe it’s a breaking change, or maybe it has security vulnerabilities. More than likely, there are things at the top that wouldn’t have been thought of if you were just thinking purely in your engineering mindset.

Deliberately thinking in this way will help you prioritize, because your time is finite.

My Failed Startup Ideas

Over the last 15 years I’ve bought over 100 domain names based on ideas for apps. I’d be excited about it, and start building something right away. I got to learn all kinds of new tools and frameworks by doing this, and got really great at knowing how to build great software. However, none of my ideas took off. Some might have been based on timing and luck, but more-so I just found it more fun to tinker, than to step back and put on my leadership hat. These experiences were invaluable to growing my engineering skillset.

Conclusion

Great ideas and companies usually have leaders or “visionaries” that can figure out the what should be done and why. Some of the most successful products have been built on the worst tech stacks you’ve ever seen. As engineers, we don’t want to always think like this, but it’s a valuable skill to have, and can help you step back and see the bigger picture of what and why.

The Best Way to Collect a Flow in Kotlin – launchIn

At some point you’ll need to collect (receive items) from a Flow (reactive stream) within a Kotlin Coroutine.  More than likely you will use a launch on a CoroutineScope, and then collect like this:

scope.launch {
  flow
    .onEach { println(it) }
    .collect()
}

This works great, but there is a better way for most use cases. It’s using a function called launchIn. What’s launchIn? It’s just shorthand to do what you did above. This is the equivalent logic as above, but using launchIn.

flow
  .onEach { println(it) }
  .launchIn(scope)

This is less code to write, but more importantly it’ll get you out of some hard to debug situations when collecting from Flows. The non obvious thing to understand is that collect() will block the coroutine until the flow has finished emitting. This behavior is sometimes desired, but for me it’s not in most cases.

In the example below, you’d think that both Flows are being collected at the same time, but flow1 is collected until the Flow finishes emitting, and then flow2 is collected until it is finished emitting.

scope.launch {
  flow1
    .onEach { println(it) }
    .collect()
  
  // Will not run until flow1 finishes emitting
  flow2
    .onEach { println(it) }
    .collect()
}

To collect both in parallel, you’d need to write this:

scope.launch {
  flow1
    .collect { println(it) }
}
scope.launch {
  flow2
    .collect { println(it) }
}

This is where launchIn comes to the rescue to make this reach much easier in my opinion. Here is the equivalent using launchIn:

myFlow1
  .onEach { println(it) }
  .launchIn(coroutineScope)
myFlow2
  .onEach { println(it) }
  .launchIn(coroutineScope)

I like launchIn because it’s less code to write, I don’t have to have indentation, and I just found it easier to understand.

In no way does this mean that the normal launch() and collect() aren’t great things to use, but for most use cases, I’d suggest considering using launchIn().

My MutableStateFlow Didn’t Emit!

I am in love with MutableStateFlow which is part of the Kotlin Coroutines Library. It makes managing state, and exposing it as a reactive Flow so easy.

You just create a MutableStateFlow(initialValue), and then you can later on just set myMutableStateFlow.value = newValue, and if it has changed, it’ll emit a new event as a reactive event on the Flow!

This is amazing, but in order to make this work the way you want it to, you HAVE to use Immutable Data Structures.

Why? Glad you asked, here we go.

How MutableStateFlow’s “value” Property Works

Just set mutableStateFlow.value=newValue and the value will be emitted! This Flow is a great way to keep track of state where you only want to emit when there is a change.

You can set your mutableStateFlow.value many times, but unless !oldValue.equals(newValue), then a new value won’t be emitted. That way subscribers don’t need to use distinctUntilChanged() to filter out duplicates.

Scenario where “My MutableStateFlow Didn’t Emit!

I’ve simplified a scenario I ran into to share how MutableStateFlow may not work the way you think you should. I banged my head on the wall trying to figure out what was happening, and hopefully this simplified example will save you a headache.

/** Class with Mutable Data */
data class SomePojo(var name: String = "placeholder")
val somePojo = SomePojo()
val mutableStateFlow = MutableStateFlow(somePojo)
println("INITIAL: ${mutableStateFlow.value}")

// Update the value
somePojo.name = "Something Different"

// Print MutableStateFlow current value, but realize the value has changed because the data in that object has been mutated
println("CURRENT: ${mutableStateFlow.value}")

// Try to assign the new value to the MutableStateFlow, but they are already equal!  This means no emissions will occur.
mutableStateFlow.value = somePojo

// The result is the same, and no value was emitted.
println("UPDATED: ${mutableStateFlow.value}")

The output will be:

INITIAL: SomePojo(name=placeholder)
CURRENT: SomePojo(name=Something Different)
UPDATED: SomePojo(name=Something Different)

How I Went Wrong

  • My state model was “SomePojo” which had a mutable var “name” on it.
  • The “somePojo” variable was initially set as mutableStateFlow.value
  • I set myPojo.name=”Something Different” to change the name.
  • I wanted to emit the new state, so set mutableStateFlow.value=somePojo.
  • My MutableStateFlow Didn’t Emit!
  • 🤔
  • The current value of mutableStateFlow.value was already set to myPojo, and I had modified the property “name” on it.
  • As seen above, MutableStateFlow.value will emit unless the oldValue.equals(newValue). Because I had modified the mutable property name, when the equals() comparison happened.
  • The value was already the same, and therefore no change occurred, and there was no emission.
  • Whoa… that’s confusing. Yes, but it makes sense now.

Conclusion

There are things you can do to avoid running into this problem. Use immutable data structures (classes with all val properties) with MutableStateFlow to avoid unexpected behavior.

If you mutate (change) the value of an object that’s currently the state of a mutable state flow, it won’t emit a new value when re-assigned because it only emits when the value has changed. In this case the mutable value has changed… but so has the underlying state, so when compared it looks as if nothing has changed.

Try for yourself with this Unit Test Gist: https://gist.github.com/handstandsam/1007031cea66e9862bed44840fafb92e

Kotlin Actors – No Drama Concurrency

Kotlin Actors are part of the Kotlin Coroutines library. I’ll walk you through the reasons why I use Kotlin Actors to achieve concurrency, while leveraging Coroutines to process reactive events in unknown order.

Concurrency?

  • Allows events to happen out-of-order or in partial order, without affecting the final outcome.
  • This allows for leveraging parallel execution without giving up determinism.

Why Does Android need Reactive Programming?

  • Click Events
  • Intents
  • Networking Requests
  • Disk Writes
  • etc.

Kotlin Coroutines?

Essentially, Kotlin Coroutines are light-weight threads. They are launched in a context of some CoroutineScope.

Kotlin Actors?

  • A Single Kotlin Coroutine
  • Processes incoming Messages
  • Backed by a Channel
  • Concurrent

Actors receive Messages (Intentions) via a Channel

Channels are the only way to safely communicate across Coroutines.

This example implements a Shopping Cart Dao from my GitHub Project ShoppingApp. I’ve created a type called Intention which are sent across the channel as messages. The intentions represent actions I want to perform, but keep my data thread safe.

sealed class Intention {
    class FindByLabel(
        val label: String,
        val deferred: CompletableDeferred<ItemWithQuantity?>
    ) : Intention()

    class Upsert(val itemWithQuantity: ItemWithQuantity) : Intention()

    class Remove(val itemWithQuantity: ItemWithQuantity) : Intention()

    object Empty : Intention()
}

Actors Process Messages Sequentially in a for() loop

These messages (Intentions) come in across a Channel from other Coroutines, get queued, and then get processed by the Actor sequentially to achieve concurrency.

scope.actor<Intention> {
    for (intention in channel) {
        // Process Messages/Intentions
        when (intention) {
            is Intention.FindByLabel -> {
                // ...
            }
            is Intention.Upsert -> {
                // ...
            }
            is Intention.Remove -> {
                // ...
            }
            is Intention.Empty -> {
                // ...
            }
        }
    }
}

Sending Messages to the Actor – send() vs offer()

To send messages to the actor, you send a message to it using actor.send(intention) or actor.offer(intention). Here are the differences between them (from the Kotlin documentation of SendChannel).

CompletableDeferred to await() Results

We send in messages to the actor, but sometimes we want to wait for a result once the message has been processed by the actor. We use CompletableDeferred to do this. We await() the result, like in this example where we are querying for a value:

class FindByLabel(
    val label: String,
    val deferred: CompletableDeferred<ItemWithQuantity?>
) : Intention()
// ---
val deferred = CompletableDeferred<ItemWithQuantity?>()
actor.send(
    Intention.FindByLabel(
        label = label,
        deferred = deferred
    )
)
val result : ItemWithQuantity? = deferred.await()

Aren’t Actors Marked with @ObsoleteCoroutineApi?

Yes, but complex actors will also support the same use cases, and there will be a clear path. Also, there is no planned replacement at this point. See the response from the Kotlin Coroutines tech lead from the GitHub issue:

Video & Slides

I was able to present this to Boston Android meetup group and 18 other meetup groups on Tuesday, July 14th which was an amazing experience. The video will be available soon and I’ll be sure to put it here. Here are the slides for now.

Links

Wrapping Mockito Mocks for Reusability

My general advice about Mockito is to try and avoid it when you can. Ryan Harter has an awesome companion post called Replacing Mocks which shows some potential pitfalls of using Mockito Mocks, as well as how to avoid using it by restructuring code. However, sometimes Mockito can be the right tool to use for mocking dependencies in a unit test when a code refactor isn’t possible due to constraints. I use Mockito-Kotlin which helps leverage Mockito in Kotlin code.

In this post I show how you can wrap a Mockito mock to avoid using verbose syntax (“whenever”, “verify”, etc.) all over the place. I call this wrapper around the Mockito mock a “Fake”.

// Fake Wrapper around Mockito Mock (See implementation below)
val fakeOven = FakeOven()

// Access and Use Mockito Mock
val oven : Oven = fakeOven.mock

// Clean API to Setup Mocks (using Wrapper)
fakeOven.givenOvenResult(OvenResult.Success)

// Clean API to Verify Mocks (using Wrapper)
fakeOven.thenOvenSetTo(temperatureFahrenheit = 350, timeMinutes = 30)

Benefits:

  • Single Responsibility – Mocking logic out of your test class.
  • Cleaner Tests – Avoid using “when”, “whenever” and “verify” all over the place.
  • Less Duplication – Can be reused across tests and for future tests you may write.

Example: Baking with an Oven

In this example we bake a Cake which requires an Oven. We need to mock the Oven.

NOTE: We could try various approaches for this example, but for the purpose of explaining this strategy, we’ll use the “Fake” Mockito wrapper.

/** Class that uses [Oven] */
class Dessert(val oven: Oven) {
    fun bakeCake(): OvenResult {
        oven.setTemperatureFahrenheit(350)
        oven.setTimeMinutes(30)
        return oven.start()
    }
}
/** Class we will use Mockito to Mock */
class Oven {
    fun setTemperatureFahrenheit(tempF: Int) {
        // ...
    }

    fun setTimeMinutes(minutes: Int) {
        // ...
    }

    fun start(): OvenResult {
        // ...
    }
}
/** Whether the Oven command was successful, or something happened */
sealed class OvenResult {
    object Success : OvenResult()
    data class Failure(val e: Exception) : OvenResult()
}

Original Test 🤷🏽‍♂️

import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import org.junit.Test

/** Test Dessert Baking */
class DessertTest {

    @Test
    fun bakeCakeSuccess() {
        val oven: Oven = mock()
        val dessert = Dessert(oven)

        // Setup
        whenever(oven.start()).thenReturn(OvenResult.Success)

        // Execute Code
        dessert.bakeCake()

        // Verification
        verify(oven).setTemperatureFahrenheit(350)
        verify(oven).setTimeMinutes(30)
    }
}

FakeOven – Mockito Mock Wrapper 🤔

/** Wraps the Mockito mock for reuse */
class FakeOven {

    val mock: Oven = mock()

    fun givenOvenResult(ovenResult: OvenResult) {
        // Setup
        whenever(mock.start()).thenReturn(ovenResult)
    }

    fun thenOvenSetTo(temperatureFahrenheit: Int, timeMinutes: Int) {
        // Verification
        verify(mock).setTemperatureFahrenheit(temperatureFahrenheit)
        verify(mock).setTimeMinutes(timeMinutes)
    }
}

Updated Test – Using Fake Mockito Wrapper ✅

class DessertTestWithFake {

    @Test
    fun bakeCakeSuccess() {
        val fakeOven = FakeOven()
        val dessert = Dessert(fakeOven.mock)

        fakeOven.givenOvenResult(OvenResult.Success)
        dessert.bakeCake()
        fakeOven.thenOvenSetTo(
            temperatureFahrenheit = 350,
            timeMinutes = 30
        )
    }
}

We use “fakeOven.mock” to fulfill the “Oven” dependency, and control the behavior using the wrapper we have created.

val fakeOven = FakeOven()
val oven : Oven = fakeOven.mock

Conclusion

Isolate usage of Mockito, and avoid scattering it all over your tests. By using this pattern of wrapping a Mockito Mock in a fake, your tests that require Mockito are a little bit better.

Unlocking Biometric Prompt – Fingerprint & Face Unlock

AndroidX Biometric gives us a single API for supporting Biometrics on Android devices via the BiometricPrompt, and a fallback Fingerprint dialog for API 23-27.  This post does a side-by-side comparison of what it looks like on the Pixel 4, Pixel 3, and an API 26 Emulator to show you what it looks like on different devices, hardware and different builder configurations.

Currently, the Pixel 4 is the only device that supports Face Unlock via the Biometric Prompt. There aren’t even emulators that support it.  I ended up with a Pixel 4, and wanted to create this post with you to save you some 💰 and⌚.

What is the Android Biometric Prompt?

The Android Biometric Prompt was released as part of the Android OS in API 28 (Pie) to replace the FingerprintManager.  Its goal is to make a standard way of interacting with Biometrics via the operating system, and also support multiple types of biometric types such as Fingerprint, Face & TBD.

One of the downsides of the Biometric Prompt is that we are asked to use the terminology “Biometric” instead of “Fingerprint” or “Face” because the BiometricManager doesn’t tell us the type of biometric the user will use.  Read more about how to provide better user experiences through tailored biometric messaging in my previous post.

Using AndroidX Biometric

I’m going to show you various configurations of the library in this post, but refer the documentation from Google for more information.

BiometricPrompt.PromptInfo.Builder()
 .setTitle("Authenticate with Face")
 .setNegativeButtonText("Cancel") 
 .setConfirmationRequired(true)
 .build()
Face Unlock Success

Face Unlock Fail & Retry

Confirmation Required

There is a configuration parameter for Biometric Prompt Info Builder called “setConfirmationRequired” which, when set to false, passively authenticates the user without any interaction (other than looking at the phone). Note: This only works for Face Unlock since a Fingerprint is confirmation.

.setConfirmationRequired(false)

.setConfirmationRequired(true)

NOTE: There is a setting which allows a user to ALWAYS confirm when using Face Unlock, so be aware of that when building your applications.

Conclusion

Use AndroidX Biometric.  It feels like they were still working out the kinks when they release Biometric Prompt in API 28.  The AndroidX Library has some device specific workarounds and the fallback dialog for API 23-27.  It’s weird that there isn’t better documentation about the user experience for each biometric type, which is why I wrote this post. Hopefully you won’t have to spend hundreds of dollars on a Pixel 4 now, and have a better idea of what the Biometric Prompt looks like under different configurations.

Links:

Companion Video on AsyncAndroid

Android Device Mirroring and Recording

Mirroring and Recording what is on your physical Android Device to your computer isn’t trivial, but is an important skill to have as a developer. Being able to share and record what you see on your Android screen is super helpful for live demos, your GitHub PRs, and blog posts. There are a lot of ways to do this, but there is no perfect way of doing it.  I’ll walk you through my flow in this post.

I used Vysor for a long time, and think it’s a great tool to use to mirror your device onto your computer.  Vysor is really easy to use, but the free version does have feature limitations such as mirroring quality, and advertisements every 15 minutes. When I tried scrcpy with my development setup, I found that for me it worked the best out of any of the other tools to do this.

See the scrcpy GitHub page for all the instructions, but if you are on a Mac, already have “adb” configured, and have homebrew, then just run brew install scrcpy.  After it’s installed you can just type “scrcpy” into your terminal and it’ll launch device mirroring.

Now that you have your Android device mirroring on your computer, you need to record it.  There are a lot of tools that allow you to screen record into a GIF, but I use Kap.  You can launch Kap via the menu bar with this icon:

Then select an area of your screen manually,

… or choose an open application window.

After you are done recording, stop the recording with the button in the menu bar.

Trim your content, select resolution, frames per second (FPS), export format (GIF, MP4), and export!

Drag and drop the file into your GitHub PR.  NOTE: 10MB is the limit for image attachments in a PR, so adjust your frames per second and image resolution to find the right size.

Your PR has a GIF of your device! 🎉 This makes your PR a lot easier to understand to a reviewer, and anyone looking back at this PR in the future.

Conclusion

Adding GIFs to PRs and blog posts really keep readers engaged.  It especially did if you are actually reading this far 😎.  I hope my you find my recommendations something that help your Android development and content creation!

Links:

Companion Video on AsyncAndroid