Jekyll2023-01-11T22:56:18+00:00https://cafonsomota.xyz/feed.xmlCarlos MotaAndroid tech lead at WIT Software, he can easily be spotted there working on the company RCS solution. An enthusiastic for new technology and always trying to reach those last 20% of all of his side projects that seem to be really far away, he loves to share his knowledge with others either by giving talks, teaching, writing or along with a cold beer in the nearest pub. GDG Coimbra organizer and Kotlin evangelist, he also has a huge passion for travel, photography, space and the occasional run.Carlos Motacafonsomota@gmail.comdroidcon Berlin 2021 — Presentations2021-10-27T00:00:00+01:002021-10-27T00:00:00+01:00https://cafonsomota.xyz/droidcon-berlin-2021-presentations<figure>
<img src="/droidcon-berlin-2021-presentations/featured.png" alt="droidcon Berlin 2021 - presentations" />
</figure>
<p>I’ve had a fantastic week at <a href="https://twitter.com/hashtag/dcbln21?src=hashtag_click">#dcbln21</a>. I couldn’t ask for a better event for us to be once again together. I’ve had the opportunity to meet numerous people in person and remember how good it feels to talk to a live audience.</p>
<p>Now that I’m back to reality, I wanted to check a couple of slides from talks that I’ve watched and as I was bookmarking them, I’ve decided to go that extra mile and try to gather them in a single post.</p>
<p><strong>Note:</strong> if you’ve found slides that are not here, please add them in the comments, that I’ll update this post.</p>
<h3 id="wednesday">Wednesday</h3>
<ul>
<li>Keynote: Why Projects Succeed: Lessons Learned from the Android OS (by Chet Haase)</li>
<li>Quick Apps: Speedy Development, Maximum Outreach (by Martin Alvarez-Espinar)</li>
<li>Writing Apps for the Work Profile (by Darryn Campbell)</li>
<li><a href="https://speakerdeck.com/himanshoe/backend-engineering-for-android-developers">Backend for Frontend — The secret of a great mobile project</a> (by Michal Szczepanik)</li>
<li>Your new Data Safety section on Google Play (by Aisha Iqbal and Tina Sriskandarajah)</li>
<li>Testing your React Native App — The Cypress way (by Janhavi Dahihande)</li>
<li>The journey of adopting Jetpack Compose in Babbel’s App (by Ahmed Mabrook and Benjamin Kadel)</li>
<li><a href="https://speakerdeck.com/ashdavies/droidcon-berlin-everything-is-an-api">Everything is an API</a> (by Ash Davies)</li>
<li>KMP for Mobile Developers (by Enrique Lopez Mañas)</li>
<li><a href="https://zsmb.co/talks/become-a-pro-in-android-studio/">Become a Pro in Android Studio</a> (by Márton Braun)</li>
<li>DataStore Preferences and migrating from SharedPreferences (by Hitesh Das)</li>
<li><a href="https://speakerdeck.com/zsmb/building-a-production-ready-chat-sdk-with-jetpack-compose-droidcon-berlin-2021">Building a Production-Ready Chat SDK Using Jetpack Compose</a> (by Filip Babić and Márton Braun)</li>
<li>Efficient Kotlin (by Marcin Moskała)</li>
<li>Kotlin Multiplatform Mobile in production: key takeaways from developing two cross-platform apps (by Lena Stepanova)</li>
<li><a href="https://speakerdeck.com/codingchick/inside-the-room-dcbln21-revised-edition">Inside the Room</a> (by Effie Barak)</li>
<li>Privacy Engineering in Android (by Pauline Anthonysamy)</li>
<li><a href="https://speakerdeck.com/jossiwolf/hitchhikers-guide-to-compose">A Hitchhiker’s Guide to Compose Compiler: Composers, Compiler Plugins, and Snapshots</a> (by Jossi Wolf and Amanda Hinchman-Dominguez)</li>
<li>Android Architecture Design with Koin (by Arnaud Giuliani)</li>
<li>KMM story — from first feature to Mobile mono-repo at Sphere (by Attila Blenesi and Anders Ha)</li>
<li><a href="https://speakerdeck.com/runningcode/what-is-the-android-cache-fix-plugin-and-why-do-i-need-to-solve-my-own-cache-misses">What is the Android Cache Fix plugin and why do I need to solve my own cache misses?</a> (by Nelson Osacky)</li>
<li>Lesson Learned from building successful android library: PhotoEditor (by Burhanuddin Rashid)</li>
<li>Testing Jetpack Compose UI (by Dmytro Shuba)</li>
<li><a href="https://kotlintesting.com/dcberlin21/">Idiomatic Kotlin in Tests</a> (by Jarosław Michalik)</li>
<li>Using GraphQL in a KMM project with Jetpack Compose and SwiftUI (by John O’Reilly)</li>
<li>Introduction to dual-screen and foldables development (by Cesar Valiente and Cristian Verdes)</li>
<li><a href="https://speakerdeck.com/oleur/game-development-with-unity-from-an-android-point-of-view-550ac739-1261-4c14-86d3-c5810ecb34ac">Game Development with Unity from an Android Point of View</a> (by Julien Salvi)</li>
<li>Feature Toggles, Trunk-Based Development and Continuous Delivery (by Alex Fedorov)</li>
<li><a href="https://speakerdeck.com/himanshoe/backend-engineering-for-android-developers">Backend Engineering for Android Developers</a> (by Himanshu Singh)</li>
<li><a href="https://speakerdeck.com/jeroenmols/the-definitive-guide-to-android-library-development">The definitive guide to Android library development</a> (by Jeroen Mols)</li>
<li>Extending the build — AGP APIs for plugin developers
(by Wojtek Kaliciński)</li>
<li>Flutter for TV platforms (by Aleksandr Denisov)</li>
<li><a href="https://www.slideshare.net/ChristianMelchior/coroutines-for-kotlin-multiplatform-in-practise">Coroutines for Kotlin Multiplatform in practise</a> (by Christian Melchior)</li>
<li><a href="https://speakerdeck.com/florianmski/becoming-a-mentor-why-and-how">Becoming a mentor, why and how?</a> (by Florian Mierzejewski)</li>
<li>How to best authenticate with non-Google identities (by Paul Ruiz)</li>
<li>Crashing is good for your App (by Seyed Jafari)</li>
</ul>
<h3 id="thursday">Thursday</h3>
<ul>
<li>Get in the fast lane; Android Automotive OS (by Juhani Lehtimäki and Pierluigi Rufo)</li>
<li><a href="https://speakerdeck.com/fgiris/using-kotlin-flow-in-mvvm">Using Kotlin Flow in MVVM</a> (by Fatih Giriş)</li>
<li><a href="https://speakerdeck.com/lnicolet/engineering-a-design-system">How we engineered our design system</a> (by Luca Nicoletti)</li>
<li>Coding and mental illness. A survival guide. (by Chris Ward)</li>
<li>Refactoring UI (by Joe Birch and Prateek Prasad)</li>
<li>From Ooops to Mobile DevOps: 7 Steps for Successful Mobile DevOps Transformation (by Moataz Nabil)</li>
<li><a href="https://t.co/lN7J3dbITK">“Offline” is not an error</a> (by Yonatan (Yoni) Levin)</li>
<li><a href="https://speakerdeck.com/abaotic/inhibiting-the-impostor">Inhibiting the impostor</a> (by Ana Baotić)</li>
<li><a href="https://speakerdeck.com/erikhellman/bluetooth-low-energy-for-modern-android-development">Bluetooth LE for Modern Android Development</a> (by Erik Hellman)</li>
<li><a href="https://speakerdeck.com/rivuchk/droidcon-berlin-tdd-in-android-with-spek">TDD in Android with Spek</a> (by Rivu Chakraborty)</li>
<li>Junioring Senior Developers (by Vladimir Jovanović)</li>
<li>Sign-in with Apple on Android devices? (by Devlin Duldulao)</li>
<li>🤖 Automating key workflows in your daily developer life! (by Alessandro Mautone)</li>
<li>Clean up state handling with a state machine (by Daniel Gergely)</li>
<li>From Opensource to Openmind (by Daniele Fontani)</li>
<li><a href="https://speakerdeck.com/aldefy/a-page-out-of-server-driven-ui-on-android">A page out of Server driven UI on Android</a> (by Adit Lal)</li>
<li>Practical tips for succeeding with CI/CD for Android (by Zan Markan)</li>
<li>‘Nitrogenize’ your project with Mvvm, Compose, UTP — A killer combination for successful deliveries (by Enrico Bruno Del Zotto)</li>
<li><a href="https://speakerdeck.com/cortinico/detekt-state-of-the-union">Detekt — State of the Union</a> (by Nicola Corti)</li>
<li><a href="https://speakerdeck.com/dinorahto/hosting-states-in-compose">Hosting our states in Compose</a> (by Dinorah Tovar)</li>
<li>Extend your reality with AR (by Anitha Manikandan)</li>
<li><a href="https://speakerdeck.com/jrodbx/keeping-your-pixels-perfect-paparazzi-1-dot-0">Keeping your Pixels Perfect 📸: Paparazzi 1.0</a> (by John Rodriguez)</li>
<li>Advanced multi-platform dependency injection (by Salomon BRYS)</li>
<li><a href="http://jfdi.jetzt/_talks/pcbs-and-android/">Printed Circuit Boards and Android: A Love Story Between Two Engineering Disciplines</a>
(by Mario Bodemann)</li>
<li>Nail your Gradle build time (by Josef Raska)</li>
<li>Scaling App development at Zalando (by Volker Leck and Alexey Agapitov)</li>
<li><a href="https://speakerdeck.com/pjwelcome/android-developing-locally-with-the-firebase-ui-emulator">Developing Locally with the Firebase UI Emulator</a> (by Peter John Welcome)</li>
<li>Offline first Flutter applications (by Salih Guler)</li>
<li>WebRTC on Android. Simplier than you thought! (by Artem Bagritsevich)</li>
<li><a href="https://speakerdeck.com/tiwiz/the-importance-of-being-tested">The Importance of Being Tested</a> (by Roberto Orgiu)</li>
<li><a href="https://speakerdeck.com/gio_sastre/an-introduction-effective-snapshot-testing-on-android">An Introduction to Effective Snapshot Testing on Android</a> (by Sergio Sastre Flórez)</li>
<li>Improve your animations skills in Flutter (by Dominik Roszkowski)</li>
<li>Gradient descent is taking away your Android developer job (by Michal Harakal)</li>
<li><a href="https://speakerdeck.com/wajahatkarim3/jetpack-compose-for-games-and-animations">Jetpack Compose for Games & Animations</a> (by Wajahat Karim)</li>
<li>Your own @Annotation processor. (by Gabriel Samojło)</li>
<li><a href="https://www.slideshare.net/SinanKOZAK/rock-solid-ui-test-droidcon-berlin-2021">Rock-Solid UI and Instrumentation Testing</a> (by Sinan Kozak)</li>
<li><a href="https://github.com/vishna/talks/blob/main/20211021-adding-flutter-to-app-DCBerlin.pdf">Adding Flutter to your app — what are they not telling you?</a> (by Łukasz Wiśniewski)</li>
<li>Understanding and debugging ANR’s (Android Not Responding) (by Dinesh Shanmugam C)</li>
<li><a href="https://dontkillmyapp.com/apidoc">How to survive on Android and don’t get killed</a> (by Petr Nalevka and Jiří Richter)</li>
<li>The Billion User Open Secret (by Abel Adugam A. Nibori)</li>
<li>Automating Android Workflows with Github Actions (by Ubiratan Soares)</li>
</ul>
<h3 id="friday">Friday</h3>
<ul>
<li>A Comedy Talk (by Chet Haase)</li>
<li>The shape of media regulation to come (by Hans-Christian Woger and Philipp Sümmermann)</li>
<li><a href="https://speakerdeck.com/fgiris/migrating-a-large-scale-banking-app-to-compose">Migrating a large-scale banking app to Compose</a> (by Fatih Giriş)</li>
<li>Enhance your single screen designed-app to make it shine on foldable devices (by Cesar Valiente and Cristian Verdes)</li>
<li><a href="https://speakerdeck.com/monikakumarjethani/a-z-of-kotlin-flow">A-Z of Kotlin Flow</a> (by Monika Kumar Jethani)</li>
<li><a href="https://github.com/falkorichter/presentations/blob/master/agile-hardware-development/hardware-development_droidcon2021.md">Agile hardware development (as an Android dev)</a> (by Falko Richter)</li>
<li>Twitter driven development and the mythical 10x developer (by Abdurahman Adilovic)</li>
<li>Climate Crisis: Can we as developers save the planet? (panel) (by Jörn Ehmann, Fred Porciúncula, Max Schulze, and Juhani Lehtimäki)</li>
<li>Kotlin’s companion: The power of IntelliJ IDEA (by Marc Reichelt)</li>
<li><a href="https://cmota.github.io/a-composable-new-world">A Composable New World!</a> (by Carlos Mota)</li>
<li>That’s how we scroll in Flutter (by Krzysztof Krasiński-Sroka, Jan Stępień, and Artur Płaczek)</li>
<li>The future of work is TBD (panel) (by Tautvydas Leonavičius, Miriam Busch, and Erik Hellman)</li>
<li>Accessibility Matters (by Aleksandar Ninevski)</li>
<li><a href="https://speakerdeck.com/budius/how-to-ask-permission-the-clean-way-droidcon-2021">How to ask permission, the clean way</a> (by Ronaldo Pace)</li>
<li>Building a books app with Jetpack Compose and Firebase (by Rosário Pereira Fernandes)</li>
<li>What they don’t tell you about feature toggles (by Ivan Damjanović)</li>
<li>Migrating your app to compose, step 1, live coding (by Richard Schattauer)</li>
<li>Engage with Firebase: How to make users to actually use your app (by Santiago Martínez)</li>
<li>Standby Buckets in Android (by Mathias Wegener)</li>
<li><a href="https://speakerdeck.com/prof18/introducing-kotlin-multiplatform-in-an-existing-project-droidcon-berlin-2021">Introducing Kotlin Multiplatform in an existing project</a> (by Marco Gomiero)</li>
</ul>
<p>Thank you <a href="https://twitter.com/droidconBerlin">@droidconBerlin</a> for putting everything together. Excellent job, as always 🙂.</p>Carlos Motacafonsomota@gmail.comTroubleshooting: KMP and undefined symbols for architecture x86_64 (iOS)2021-09-22T00:00:00+01:002021-09-22T00:00:00+01:00https://cafonsomota.xyz/troubleshooting-kmp-and-undefined-symbols-for-architecture-x86-x64-ios-adb<figure>
<img src="/troubleshooting-kmp-and-undefined-symbols-for-architecture-x86-x64-ios-adb/featured.jpeg" alt="Troubleshooting: KMP and undefined symbols for architecture x86_64 (iOS) cover" />
</figure>
<p>As a new version of Xcode was released, I started my day thinking what would happen if I made that update and then compiled my Kotlin Multiplatform project.</p>
<p>According to my CI, the answer is no:</p>
<blockquote>
<p>The /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld command returned non-zero exit code: 1. output: ld: warning: ignoring file /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/13.0.0/lib/darwin//libclang_rt.ios.a, missing required architecture x86_64 in file /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/13.0.0/lib/darwin//libclang_rt.ios.a (4 slices) Undefined symbols for architecture x86_64: “___cpu_model”, referenced from: _Kotlin_String_hashCode in result.o ld: symbol(s) not found for architecture x86_64</p>
</blockquote>
<p>I’m running on a Mac M1 (Apple Silicon) with Kotlin 1.5.10.</p>
<p>Fortunately, the issue is simple to solve, you just need to <strong>bump Kotlin version to <a href="https://blog.jetbrains.com/kotlin/2021/08/kotlin-1-5-30-released/">1.5.30</a></strong> (where we got native support for Apple Silicon) or even better to 1.5.31 that was released this week.</p>
<p>With this, you can also remove the tick on “Open with Rosetta” from Xcode properties (Get Info) and take full advantage of M1.</p>
<p><strong>Note:</strong> If you’re compiling your project to JS, updating to 1.5.30/1 will most certainly increase your library size. For now, I’ve decided to have different versions depending on the target to which I’m compiling the project.</p>
<p>Do you have a better approach? Something didn’t quite work with you?</p>
<p>Feel free to reply here or send me a message 🙂</p>Carlos Motacafonsomota@gmail.comReaching the first 30k views2021-08-31T00:00:00+01:002021-08-31T00:00:00+01:00https://cafonsomota.xyz/reaching-the-first-30k<p>After writing this post we’ve noticed that there’s a lot to say about the online edition of the Android Training Program. More than ten pages to be precise. So we’ve decided to split this into two: a TL;DR section where you can read a brief resume of the program and a pocket book version that you can find next.</p>
<h2 id="tldr">TL;DR</h2>
<p>The Android Training Program started back in 2018. It’s initial goal was to visit different Universities or Polytechnics across Portugal and spend a day teaching students the basics of Android development as well as how they could keep improving their skills — along with Codelabs and Udacity programs. We’ve held 14 events across 11 different academic institutions and were able to teach the wonders of Android development to around 3300 students that we hope today are app developers.</p>
<p>Due to the pandemic, as people started working from home, we needed to rethink the 2020 edition. In-person events were no longer an option, and we wanted to keep everyone engaged with the program — so it needed to be interesting and at the same time enjoyable, otherwise people would just log off.</p>
<p>One of the first decisions that we took was switching to Portuguese entirely. This removed any barrier that the language can create, and allowed us to reach students from different Portuguese speaking countries — such as Brazil, Mozambique, Angola, and Cape Verde.</p>
<p>We’ve gathered feedback from various academic institutions which were already teaching online and created a partnership with them: they shared the program across their teachers, mailing lists and student nuclei and from our side we could give them visibility and all the free content produced for our classes that they could later use.</p>
<p>This edition of the ATP was 12 classes, during which we covered not only the basics like activities, fragments, UI Components, etc., but also taught about more complex issues, eg. Jetpack libraries like the CameraX, Room, Paging and we even gave a quick glimpse at Compose. We’ve talked about Firebase and Machine Learning, namely TensorFlow Lite.</p>
<p>This way we could reach a broad audience and tackle more advanced concepts that sometimes seem to be a little left behind.</p>
<p>Each episode was set to be 1h30 long and was split in half: for the first 40 minutes we were focusing on theory and the other 40 on practice. For the remaining 10 minutes, we’ve always had an invited speaker to talk a bit more about a specific subject. We were lucky enough to have people from Google, GDE’s, community organizers, Universities, startups, etc. Our most sincere thank you to them all!</p>
<p>Along with the live classes, we also created a Discord server where anyone could ask us questions and share additional feedback at any time. This is still going strong as we keep receiving new questions weekly.</p>
<p>We couldn’t be prouder of the final result of the program as we managed to record more than 25 hours of content with the support of developer advocates from Google and key members of the Portuguese ecosystem, creating a huge community of ~5000 participants (80% from Portugal, 15% from Brazil, and 5% from Africa), with ~3000 subscriptions in Youtube, delivering +30000 views, and 2000 participants in our Discord channel. And you know what? All in Portuguese.</p>
<figure>
<img src="https://miro.medium.com/max/1400/0*-xy-jOnQZ0zmRpIj" alt="Screenshot from the last ATP 2020 class" />
<figcaption>Screenshot from the last ATP 2020 class 🎅
</figcaption>
</figure>
<p>We’ve had an amazing run these past years with the Android Training Program, and we’re just getting started! Do you want to start a similar program in your country or community? Feel free to reach us, our DM’s are open: <a href="http://twitter.com/davilagrau">@davilagrau</a> <a href="http://twitter.com/cafonsomota">@cafonsomota</a> and <a href="http://twitter.com/tallnato">@tallnato</a>.</p>
<p>The team of ATP (Android Training Program):</p>
<ul>
<li>Andres-Leonardo Martinez-Ortiz</li>
<li>Carlos Mota</li>
<li>Renato Almeida</li>
</ul>
<h2 id="reaching-the-first-30k-views-long-version">Reaching the first 30k views (long version)</h2>
<p>Just like many stories, this one also starts with once upon a time… in 2018 we’ve been lucky enough to be challenged by Andres-Leonardo Martinez-Ortiz, or as most of you know him — Almo, to start an ambitious project — Android Training Program (ATP). For the first two years the program was held at Portuguese Universities and Polytechnics throughout the country with the aim of teaching students how they could start developing Android applications.</p>
<p>Since those initial classes three years ago, we’ve held 14 events across 11 different academic institutions and were able to teach the wonders of Android development to around 3300 students that we hope today are app developers.</p>
<figure>
<img src="https://miro.medium.com/max/700/0*hlYPwSsDcyaCofIV" alt="Android Training Program in person @ Aveiro’s University" />
<figcaption>Android Training Program in person @ Aveiro’s University
</figcaption>
</figure>
<p>While we were planning the 2020 edition, due to the pandemic all the in-person events were shut down and Portugal made a shift to working from home.</p>
<p>Developers started figuring out how to deal with this new scenario, moving fast to the online world. For ATP there were only two options: we could either reinvent the program to be online-friendly or cancel it. Analyzing our strengths we realized we had no experience in carrying out online programs, no experience in video production, no experience in learning programs lasting several weeks, no experience in online engagement and digital marketing; the decision was clear: we will try it. Nothing but failure was guaranteed. Unless…</p>
<p>After several months of hard work, we’re proud to share with you a different story: we launched a 12 weeks program covering everything from Android basics to machine learning for mobile applications, Firebase, and some discussion about new trends such as Flutter.</p>
<p>We’ve engaged not just with our past edition partners but also with new ones in Brazil and Portuguese-speaking countries in Africa i.e. Mozambique, Angola, and Cape Verde. We recorded more than 25 hours of content with the support of developer advocates from Google and key members of the Portuguese ecosystem, creating a huge community of ~5000 participants (80% from Portugal, 15% from Brazil, and 5% from Africa), with ~3000 subscriptions in Youtube, delivering +30000 views, and 2000 participants in our Discord channel. And you know what? All in Portuguese.</p>
<h2 id="chapter-i-preparation">Chapter I: Preparation</h2>
<p>We started planning the program six months before the first class. Since we were going for a different format, we had a lot to decide and prepare before starting:</p>
<ul>
<li>How can we reach students?</li>
<li>How long is the program going to be?</li>
<li>How can we keep students engaged?</li>
</ul>
<p>We knew that it was easier to reach students in a physical space, plus during the working days everyone was already at the University. Seeing a huge Android along with posters pointing towards a room was the perfect reminder for anyone to attend. For those that get easily distracted, We used to be at the site a couple of hours before the event just to reach those who get distracted easily or may have missed the announcements.</p>
<figure>
<img src="https://miro.medium.com/max/700/0*tEmjMKLHontEQlus" alt="Android Training Program figurine" />
<figcaption>Android Training Program figurine
</figcaption>
</figure>
<p>Moving online turned out great because we’re no longer restricted to a single city, but at the same time it’s more difficult to remind students that there’s an event happening, especially after a full day of classes.</p>
<p>It’s also harder to keep them engaged while watching a presentation. Leaving a full auditorium is more difficult than just closing the browser. So we needed to come up with clever ways to keep them interested during all classes!</p>
<h2 id="chapter-ii-creating-an-audience">Chapter II: Creating an audience</h2>
<p>Working with our partners’ network, we expanded the number of participants in the program and were able to invite participants from Portugal, Brazil, and Portuguese-speaking African speaking countries, and try to reach the biggest number of people. We definitely challenged the six handshakes rule that says that we can reach anyone in the world by just talking to six different people connected within. And it was true.</p>
<p>We’ve scheduled dozens of meetings with deans, teachers, and student nucleus to understand the current mobile development state at the University/Polytechnical level and how we could complement their classes with the ATP. Moreover, they were already teaching online for a couple of months, so their feedback helped us to make a couple of tweaks to the program.</p>
<p>These meetings’ goal was to establish a partnership with them. From our side, we could give them visibility and free content they could later in classes, and in return, we asked if they could share the program through their mailing lists, classes, and colleague teachers. This allowed us to reach a high number of students.</p>
<p>Along with the academic institutions we were also able to reach Portuguese communities and technological blogs that immediately fell in love with the program and kept reminding their readers about the ATP. We’d like to express our deepest gratitude for that.</p>
<h2 id="chapter-ii-recreating-the-program">Chapter II: (re)Creating the program?</h2>
<p>Here in Portugal, each University and Polytechnic is free to create the program of their course in Informatics Engineering. There are academic institutions that lecture mobile development, while others don’t. Those who do, typically teach about the different platforms and languages without focusing on a single one, so students end up having more horizontal than vertical knowledge.</p>
<p>We noticed that most of them went for Java instead of Kotlin. This represented an additional challenge as we needed to teach at least the basics of Kotlin, otherwise after the initial class we might end up losing a lot of students who don’t know it. We saw this as an opportunity to reach a broad audience, and all the classes had a specific section focused on the language itself. Along with this we also provided extra content so students could learn more about it after hours.</p>
<p>Our previous experience showed us that part of the class needed to be dedicated to installing Android Studio, running a sample project, and having the phone/emulator configured. Having this in mind, we’ve started the program with class #0, just focused on the setup and troubleshooting. It’s important to remember that Android Studio runs on Mac, Windows, and Linux, so you’ll find a couple of problems along the way.</p>
<p>While discussing and iterating about the ATP classes, we all thought that it would be a good idea to create an application from scratch, and in each class add new features on top. First, this would work as a sample app for students to revisit at any time, and second, it’d be something where they could apply and consolidate what they’ve learned in that class.</p>
<p>We’ve built a dog breed app capable of identifying a dog. Fifi, a Yorkshire Terrier, a pet of one of the teachers helped us with testing and made everyone laugh at each appearance.</p>
<figure>
<img src="https://miro.medium.com/max/700/0*_ZGxzkDvU0WRkLUU" alt="Fifi, ATP background actor" />
<figcaption>Fifi, ATP background actor
</figcaption>
</figure>
<p>During these 12 classes, we’ve covered not only the basics like activities, fragments, UI Components, etc., but also Jetpack libraries like the CameraX, Room, Paging. We even gave a quick glimpse at Compose. We’ve also talked about Firebase and Machine Learning, namely TensorFlow Lite. This way we could reach a broad audience and tacklemore advanced concepts that sometimes seem to be a little left behind.</p>
<p>Each episode was set to be 1h30 long and was split in half: for the first 40 minutes we were focusing on theory and the last 40 on practice. For the remaining 10 minutes, we invited a speaker to talk a bit more about a specific subject. We were lucky enough to have people from Google, GDE’s, community organizers, Universities, startups, etc. Our most sincere thank you to them all!</p>
<p>Along with these 12 classes, during the program, we’ve gathered feedback and felt that we could make a couple of tweaks so along with the classes we also created a set of CodeLabs that students could follow on their time and some small videos that we happily called them bits & bytes that were about 8 minute long videos teaching a specific concept that someone as asked us.</p>
<p>You can find the entire content online at our YouTube channel (let me grab my YouTuber hat: don’t forget to subscribe!).</p>
<figure>
<img src="https://miro.medium.com/max/700/0*rjEpJ2ARMqas98Wx" alt="ATP 2020 team along with all of the participants" />
<figcaption>ATP 2020 team along with all of the participants
</figcaption>
</figure>
<h2 id="chapter-iii-what-was-our-setup">Chapter III: What was our setup?</h2>
<p>We wanted to minimize the effort of recording a class so there were a couple of requirements that we needed to define:</p>
<ul>
<li>Setting up a class and making it live easily (and available afterward).</li>
<li>Support screen sharing.</li>
<li>Support at least three participants at any time.</li>
<li>Possibility to change the screen layouts depending on who was speaking.</li>
</ul>
<p>After analyzing a wide range of solutions out there we’ve decided to go with Streamyard.</p>
<p>To prepare the classes, we used the services that Google provides for free: Docs where we’ve defined each class plan along with the resources that we wanted to share on a post email and Slides for preparing the class. Everything was done asynchronously so we needed tools that simplified collaboration and allowed everyone to edit the same document at the same time.</p>
<p>People have different schedules and sometimes live in different time zones, so we needed to have a common place where we could share additional content and ask us questions asynchronously. We’ve opted in with Discord, because most of the students are already familiar with it and it allows an unlimited history. If someone entered in the middle of the course they could just search for previous materials or questions made.</p>
<p>Our main setup was our laptops along with an external monitor which is incredibly useful for screen sharing, Asana, Google Docs and Slides, a StreamYard and YouTube account, Discord server, and of course — Android Studio, we never go anywhere without it.</p>
<figure>
<img src="https://miro.medium.com/max/700/0*xd8Hkr09cFhnqRXy" alt="Android Training Program — Class #6 cover" />
<figcaption>Android Training Program — Class #6 cover
</figcaption>
</figure>
<h2 id="chapter-iv-stories">Chapter IV: Stories</h2>
<p>We’ve encountered some great stories along the way. As we’ve mentioned before, all the classes were taught live, which means that if there was a chance that something could go wrong it most certainly did (as it’s stated by Murphy’s law). So we needed to be prepared for everything and keep in mind that we’re all going through the same scenario, so if anything happens, it’s important to try to relax and use a bit of humor — everything will be fine. And it was! Here are a couple of things that happened during the streams:</p>
<ul>
<li>Android Studio crashed in the middle of a class. After that initial panic, we remembered that we could just <a href="https://downloadmoreram.com/">download more RAM</a> and try to open it again. It didn’t work and we needed to get some more. One of our guests just lost their internet connection during one of the interviews. Fortunately, the meeting was close to an end and we were able to wrap it off. Nonetheless, no one had the chance to ask questions, so what we did was to ask the students to send them directly to us, and then we would redirect them to the interviewer to get the answers. The next day they all received an email with the contents of that talk along with all the answers.</li>
<li>Playing with Machine Learning is always fun! Especially when you want to make a demonstration of a sample that uses your computer camera to detect your arms so you can command an orchestra and it decides to not identify them at that moment, although it worked perfectly fine some hours before. So you end up spending a couple of minutes waving while a couple of hundred people are on the other side of the screen just laughing. Did you like this story? If so, give it a try — you can find the experiment <a href="https://experiments.withgoogle.com/semi-conductor">here</a>. Feel free to share your wave movements with us.</li>
<li>Each episode was scheduled to be around 1h30, but we always ran out of time. We interacted with the audience twice during each session: during the interview with our guests and at the end when we answered questions. These two sections easily went over time. Our last class was over 4 hours long — and the number of participants stayed roughly the same from the beginning till the end. Yes, it’s as tough as you might think to be speaking all this time, especially when it’s your dinner time and you’re really hungry; but it was really worth it. All the conversations and questions were really engaging and we’ve all had a great time and well, and we couldn’t ask for a better last episode of the season!</li>
</ul>
<h2 id="chapter-v-whats-next">Chapter V: What’s next?</h2>
<p>We’re currently planning this year’s edition of the program. All the content is already online so instead of repeating it, we’re focusing on new things that are being released and gaining a lot of attention among developers. One of them is Jetpack Compose.</p>
<p>The community is still going strong on Discord and the questions made there are getting more and more difficult as time goes by, which means that the next generation of Android developers is going strong with their apps.</p>
<p>We’ve had an amazing run these past years with the Android Training Program, and we’re just starting! Do you want to start a similar program in your country or community? Feel free to reach us, our DM’s are open: <a href="http://twitter.com/davilagrau">@davilagrau</a> <a href="http://twitter.com/cafonsomota">@cafonsomota</a> and <a href="http://twitter.com/tallnato">@tallnato</a>.</p>
<p>The team of ATP (Android Training Program):</p>
<ul>
<li>Andres-Leonardo Martinez-Ortiz</li>
<li>Carlos Mota</li>
<li>Renato Almeida</li>
</ul>Carlos Motacafonsomota@gmail.comAfter writing this post we’ve noticed that there’s a lot to say about the online edition of the Android Training Program. More than ten pages to be precise. So we’ve decided to split this into two: a TL;DR section where you can read a brief resume of the program and a pocket book version that you can find next.Android 12: don’t forget to set android:exported on your activities, services, and receivers2021-07-26T00:00:00+01:002021-07-26T00:00:00+01:00https://cafonsomota.xyz/android-12-dont-forget-to-set-android-exported-on-yout-activities-services-and-receivers<figure>
<img src="/android-12-dont-forget-to-set-android-exported-on-yout-activities-services-and-receivers/featured.jpeg" alt="Android 12: don’t forget to set android:exported on your activities, services, and receivers cover
" />
</figure>
<h2 id="tldr">TL;DR</h2>
<p>If you’re targeting Android 12, you need to set <code class="highlighter-rouge">android:exported</code> on each activity, service, and receiver on your <strong>AndroidManifest.xml</strong> file.</p>
<p>This recently happened to me while updating one of my apps to Android 12 (API 31). As I’d incremented the SDK version and hit build, the process failed with the error:</p>
<blockquote>
<p>Error: Apps targeting Android 12 and higher are required to specify an explicit value for <code class="highlighter-rouge">android:exported</code> when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.</p>
</blockquote>
<p><strong>Note:</strong> the building process fails if you’re using Android Studio 2020.3.1 Canary 11 or later.</p>
<h2 id="introduction">Introduction</h2>
<p>The <code class="highlighter-rouge">exported</code> attribute is used to define if an activity, service, or receiver in your app is accessible and can be launched from an external application.</p>
<p>As a practical example, if you try to share a file you’ll see a set of applications available. Clicking on one of them will open the activity responsible to handle that file, which means that it’s declared on the Manifest with <code class="highlighter-rouge">exported:true</code>.</p>
<p>Activities that declare <strong>intent filters</strong> are enabled by default, which makes sense since they typically will respond to a specific action that can be triggered by other applications.</p>
<p>It’s really important to check each one of your AndroidManifest declarations to see if they really need to be made available externally or not. Otherwise, an unwanted application might be able to interact with your app, accessing activities or services that it isn’t supposed to.</p>
<p>Making it mandatory to define the <code class="highlighter-rouge">exported</code> value of each activity, service, and receiver adds a new layer of security. Since the developer will need to set it in order to compile the app to Android 12.</p>
<h3 id="ive-got-every-activity-service-and-receiver-setting-the-androidexported-attribute-and-im-still-seeing-the-same-error">I’ve got every activity, service, and receiver setting the android:exported attribute and I’m still seeing the same error</h3>
<p>This also happened to me.</p>
<p>If your using external libraries that add any of these components to your Manifest file and they aren’t prepared for this new rule you’ll need to add them individually.</p>
<h3 id="how-do-you-know-which-libraries-are-adding-these-components">How do you know which libraries are adding these components?</h3>
<p>Analyze your application merged manifest file for these unknown components. You can easily do that by clicking on the tab <strong>Merged Manifest</strong>:</p>
<figure>
<img src="https://miro.medium.com/max/669/1*eT0nvNesYdHi06LqV6m6mg.png" alt="Generic Android Manifest file with Text/Merged Manifest actions" />
<figcaption>Generic Android Manifest file with Text/Merged Manifest actions
</figcaption>
</figure>
<p>And now looking at the merged manifest file, I immediately notice an activity that I don’t recognize:</p>
<figure>
<img src="https://miro.medium.com/max/681/1*9ctkQcayld-D5R8ELzrHGw.png" alt="Generic merged manifest
" />
<figcaption>Generic merged manifest
</figcaption>
</figure>
<p>In this case, the library that I was using for backporting the newly added SplashScreen added an activity to the <strong>AndroidManifest.xml</strong>.</p>
<p>The fix is quite simple, I just need to manually add to the Manifest file:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p"><</span><span class="n">activity</span>
<span class="n">android</span><span class="p">:</span><span class="n">name</span><span class="p">=</span><span class="s">"...test.SplashScreenAppCompatTestActivity"</span>
<span class="n">android</span><span class="p">:</span><span class="n">exported</span><span class="p">=</span><span class="s">"false"</span><span class="p">/></span>
</code></pre></div></div>
<p>And that’s it!</p>
<h3 id="troubleshooting">Troubleshooting</h3>
<p>If the merged manifest file is not being displayed, try to reduce the SDK version to API 30 and synchronize your project. Once you’ve identified which activities, services, or receivers were merged, add them to your manifest file and update the API back to version 31.</p>
<p>Do you have a better approach? Something didn’t quite work with you?</p>
<p>Feel free to reply here or send me a message directly on <a href="https://twitter.com/cafonsomota">Twitter</a> 🙂.</p>Carlos Motacafonsomota@gmail.comRay Wenderlich: WindowInsets Handling & Keyboard Animations2021-07-20T00:00:00+01:002021-07-20T00:00:00+01:00https://cafonsomota.xyz/rw-windowinsets-handling-&-keyboard-animations<p>This video course is part of the <a href="https://www.raywenderlich.com/21630989-windowinsets-handling-keyboard-animations">Android & Kotlin Tutorials on Ray Wenderlich</a>.</p>
<figure>
<img src="/rw-windowinsets-handling-&-keyboard-animations/rw-windowinsets-handling-&-keyboard-animations.png" alt="Website preview" />
<figcaption>Preview of WindowInsets Handling & Keyboard Animations</figcaption>
</figure>Carlos Motacafonsomota@gmail.comThis video course is part of the Android & Kotlin Tutorials on Ray Wenderlich.Ray Wenderlich: Speed up Your Android RecyclerView Using DiffUtil2021-05-31T00:00:00+01:002021-05-31T00:00:00+01:00https://cafonsomota.xyz/rw-speed-up-your-android-recyclerview-using-diffutil<p>This article is part of the <a href="https://www.raywenderlich.com/21954410-speed-up-your-recyclerview-with-diffutil">Android & Kotlin Tutorials on Ray Wenderlich</a>.</p>
<figure>
<img src="/rw-speed-up-your-android-recyclerview-using-diffutil/rw-speed-up-your-android-recyclerview-using-diffutil_preview.png" alt="Website preview" />
<figcaption>Preview of Speed up Your Android RecyclerView Using DiffUtil</figcaption>
</figure>Carlos Motacafonsomota@gmail.comThis article is part of the Android & Kotlin Tutorials on Ray Wenderlich.Getting… your KMP project into npm2021-04-27T00:00:00+01:002021-04-27T00:00:00+01:00https://cafonsomota.xyz/getting-your-kmp-project-into-npm<figure>
<img src="/getting-your-kmp-project-into-npm/featured.jpeg" alt="Getting… your KMP project into npm" />
</figure>
<h1 id="getting-your-kmp-project-into-npm">Getting… your KMP project into npm</h1>
<p>I’ve recently had to configure my Kotlin Multiplatform shared module to work with npm. I’m more familiar with Gradle, so configuring everything to use <strong>npm</strong> had a couple of challenges.</p>
<h2 id="using-nexus">Using Nexus</h2>
<p>I’m already using Nexus to store artifacts for the mobile builds. Nonetheless, those use maven, so in order to use <strong>npm</strong> you’ll need to create new repositories:</p>
<ol>
<li><strong>npm-private</strong> repository for your packages</li>
<li><strong>npm-proxy</strong> to access the official registry</li>
<li><strong>npm-group</strong> to access the above repositories under a single URL</li>
</ol>
<p>The <a href="https://blog.sonatype.com/using-nexus-3-as-your-repository-part-2-npm-packages">blog.sonatype</a> contains all the steps required to create these three repositories.</p>
<h2 id="adding-credentials">Adding credentials</h2>
<p>If your repository is behind credentials, you’ll need to define your username/password before publishing it.</p>
<h3 id="creating-the-npm-configuration-file-npmrc">Creating the npm configuration file (.npmrc)</h3>
<p>To do this, you can use the <strong>.npmrc</strong>. This is a configuration file for <strong>npm</strong> where you can define a set of variables. In this case, you’re going to define the registry along with the user authentication.</p>
<p>The easiest way to see where this config file is located is to run the command:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm config <span class="nb">ls</span> <span class="nt">-l</span>
</code></pre></div></div>
<p>It will output a set of variables, one of them is the userconfig. Typically, it’s under:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Users/<span class="k">${</span><span class="nv">whoami</span><span class="k">}</span>/.npmrc
</code></pre></div></div>
<p><strong>Note:</strong> If this file isn’t created, you can do it via the logic command:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm login
</code></pre></div></div>
<h3 id="configuring-your-credentials">Configuring your credentials</h3>
<p>Open the <strong>.npmrc</strong> file and add your repository and user configurations:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">registry</span><span class="o">=</span>https://<your_url>/repository/npm-group/
<span class="nv">email</span><span class="o">=</span>your@email.com
always-auth<span class="o">=</span><span class="nb">true
</span><span class="nv">_auth</span><span class="o">=</span><<span class="nb">base64</span><span class="o">></span>
</code></pre></div></div>
<p>Looking at this configuration in more detail, you have:</p>
<ul>
<li><strong>registry</strong>, corresponds, to the npm group repository that you’ve configured before</li>
<li><strong>email</strong>, your email</li>
<li><strong>always-auth</strong>, forces npm to always require authentication when accessing registry.</li>
<li><strong>_auth</strong>, authentication using base64.</li>
</ul>
<p>In order to calculate the base64 value of your username and password, you can enter:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="nt">-n</span> ‘<your_username>:<your_password’ | openssl <span class="nb">base64</span>
</code></pre></div></div>
<h3 id="creating-a-test-project">Creating a test project</h3>
<p>To test if everything is working, create a new package and publish it.
Start by creating an empty folder:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>npm-test
</code></pre></div></div>
<p>Enter in it:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>npm-test
</code></pre></div></div>
<p>Create a new <strong>npm</strong> package:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm init <span class="nt">-y</span>
</code></pre></div></div>
<p>The flag <code class="highlighter-rouge">-y</code> is used to generate the <strong>package.json</strong> already pre-filled.</p>
<p>Add a <strong>.js</strong> file</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">touch </span>index.js
</code></pre></div></div>
<p>Now that the project is created, update the <strong>package.json</strong> and add the <code class="highlighter-rouge">publishConfig</code> attribute properly configured:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">{</span>
<span class="s2">"name"</span>: <span class="s2">"npm-test"</span>,
<span class="s2">"version"</span>: <span class="s2">"1.0.0"</span>,
<span class="s2">"description"</span>: <span class="s2">""</span>,
<span class="s2">"main"</span>: <span class="s2">"index.js"</span>,
<span class="s2">"publishConfig"</span>: <span class="o">{</span>
<span class="s2">"registry"</span>: <span class="s2">"https://<your_url>/repository/npm-private/"</span>
<span class="o">}</span>,
<span class="s2">"scripts"</span>: <span class="o">{</span>
<span class="s2">"test"</span>: <span class="s2">"echo </span><span class="se">\”</span><span class="s2">Error: no test specified</span><span class="se">\”</span><span class="s2"> && exit 1"</span>
<span class="o">}</span>,
<span class="s2">"keywords"</span>: <span class="o">[]</span>,
<span class="s2">"author"</span>: <span class="s2">""</span>,
<span class="s2">"license"</span>: <span class="s2">"ISC"</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Remember that the <code class="highlighter-rouge">registry</code> URL corresponds to the private repo that you’ve created before.</p>
<p>Now that everything is configured, enter:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm publish
</code></pre></div></div>
<p>You should see an output similar to this one:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm notice
npm notice 📦 npm-test@1.0.0
npm notice <span class="o">===</span> Tarball Contents <span class="o">===</span>
npm notice 0 index.js
npm notice 324B package.json
npm notice <span class="o">===</span> Tarball Details <span class="o">===</span>
npm notice name: npm-app1
npm notice version: 1.0.0
npm notice package size: 333 B
npm notice unpacked size: 324 B
npm notice shasum: 1574f9b6d9cc94df4a5e3e56a2300b004dca229a
npm notice integrity: sha512-QW3/j4Ke3OyMr[…]gBgMfEvjrzmlw<span class="o">==</span>
npm notice total files: 2
npm notice
</code></pre></div></div>
<h2 id="publishing-the-kmp-js-module">Publishing the KMP JS module</h2>
<p>Now that you’ve confirmed that everything is working fine it’s time to publish the JS artifact that you’ve created from your shared module. So it can later be used from your web project.</p>
<p>Don’t forget that if you building for the web, you’ll need to add it as a platform. On <strong>build.gradle.kts</strong> add:</p>
<div class="language-gradle highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">js</span><span class="o">(</span><span class="n">LEGACY</span><span class="o">)</span> <span class="o">{</span>
<span class="n">binaries</span><span class="o">.</span><span class="na">executable</span><span class="o">()</span>
<span class="n">browser</span><span class="o">()</span>
<span class="o">}</span>
<span class="k">sourceSets</span> <span class="o">{</span>
<span class="n">val</span> <span class="n">jsMain</span> <span class="n">by</span> <span class="n">getting</span> <span class="o">{</span>
<span class="c1">//add any dependency here</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Now that everything is set up, enter:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gradle build
</code></pre></div></div>
<p>To generate a build to all the platforms that you’ve defined.</p>
<p>After your build ends successfully, you should have a <strong>build</strong> folder with a <strong>js</strong> subfolder that contains:</p>
<ul>
<li>node_modules</li>
<li>packages</li>
<li>packages_imported</li>
<li>package.json</li>
</ul>
<p>Looking at all the files and folders, the <strong>package.json</strong> holds all the project metadata required by <strong>npm</strong>. Similar to what you’ve done in the previous section, you’ll need to add the <code class="highlighter-rouge">publishConfig</code> attribute to your (private) repository.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"publishConfig"</span>: <span class="o">{</span>
<span class="s2">"registry"</span>: <span class="s2">"https://<your_url>/repository/npm-private/"</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Sometimes, you also need to define version.</p>
<p>An example of a correct <strong>package.json</strong> is:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">{</span>
<span class="s2">"name"</span>: <span class="s2">"shared"</span>,
<span class="s2">"version"</span>: <span class="s2">"1.0"</span>,
<span class="s2">"publishConfig"</span>: <span class="o">{</span>
<span class="s2">"registry"</span>: <span class="s2">"https://<your_url>/repository/npm-private/"</span>
<span class="o">}</span>,
<span class="s2">"workspaces"</span>: <span class="o">[</span>
<span class="s2">"packages/shared"</span>
<span class="o">]</span>,
<span class="s2">"resolutions"</span>: <span class="o">{}</span>,
<span class="s2">"devDependencies"</span>: <span class="o">{}</span>,
<span class="s2">"dependencies"</span>: <span class="o">{}</span>,
<span class="s2">"peerDependencies"</span>: <span class="o">{}</span>,
<span class="s2">"optionalDependencies"</span>: <span class="o">{}</span>,
<span class="s2">"bundledDependencies"</span>: <span class="o">[]</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Now that everything is set, just enter:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm publish
</code></pre></div></div>
<p>And your package should be successfully deployed.</p>
<h2 id="using-your-newly-created-package">Using your newly created package</h2>
<p>Now that you’ve successfully published your package, you can use it in your project via:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install </span>shared@1.0
</code></pre></div></div>
<p>That’s it!</p>
<p>Do you have a better approach? Something didn’t quite work with you?</p>
<p>Feel free to reply here or send me a message directly on <a href="https://twitter.com/cafonsomota">Twitter</a> 🙂.</p>Carlos Motacafonsomota@gmail.comGetting… your BottomSheetScaffold working on Jetpack Compose Beta 032021-03-29T00:00:00+01:002021-03-29T00:00:00+01:00https://cafonsomota.xyz/getting-your-bottomsheetscaffold-working-on-jetpack-compose-beta-03<figure>
<img src="/getting-your-bottomsheetscaffold-working-on-jetpack-compose-beta-03/featured.jpeg" alt="Getting… your BottomSheetScaffold working on Jetpack Compose Beta 03 cover" />
</figure>
<h1 id="getting-your-bottomsheetscaffold-working-on-jetpack-compose-beta-03">Getting… your BottomSheetScaffold working on Jetpack Compose Beta 03</h1>
<p>Getting… your BottomSheetScaffold working on Jetpack Compose Beta 03 cover image</p>
<p>It’s Monday, no releases this week, and… there’s a new version of Jetpack Compose — beta 03—available. What a perfect time to just increment 02 to 03 and see what’s new.</p>
<p>The API is (almost) final so after updating from alpha to beta there weren’t any big changes to do. However, and remember that’s still in development, there’s always something that I need to update. Sometimes the behavior changes, other times I wasn’t doing things right, like this one.</p>
<h2 id="bottomsheetscaffold">BottomSheetScaffold</h2>
<p>The <code class="highlighter-rouge">BottomSheetScaffold</code> allows you to show a bottom sheet in your app quite easily. You just need to define</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">val</span> <span class="py">bottomSheetScaffoldState</span> <span class="p">=</span> <span class="n">rememberBottomSheetScaffoldState</span><span class="p">(</span>
<span class="n">bottomSheetState</span> <span class="p">=</span> <span class="n">rememberBottomSheetState</span><span class="p">(</span>
<span class="n">initialValue</span> <span class="p">=</span> <span class="n">BottomSheetValue</span><span class="p">.</span><span class="n">Collapsed</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="n">BottomSheetScaffold</span><span class="p">(</span>
<span class="n">sheetContent</span> <span class="p">=</span> <span class="p">{</span>
<span class="c1">// The content you want to show in your bottom sheet</span>
<span class="p">},</span>
<span class="n">scaffoldState</span> <span class="p">=</span> <span class="n">bottomSheetScaffoldState</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// The content you want to show in your screen*</span>
<span class="p">}</span>
<span class="p">)</span>
</code></pre></div></div>
<p>And when you want to show it just call:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bottomSheetScaffoldState</span><span class="p">.</span><span class="n">bottomSheetState</span><span class="p">.</span><span class="n">expand</span><span class="p">()</span>
</code></pre></div></div>
<p>or to hide it:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bottomSheetScaffoldState</span><span class="p">.</span><span class="n">bottomSheetState</span><span class="p">.</span><span class="n">collapse</span><span class="p">()</span>
</code></pre></div></div>
<h3 id="updating-to-beta0102">Updating to beta01–02</h3>
<p>When <strong>beta 01</strong> was launched you could no longer call:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bottomSheetScaffoldState</span><span class="p">.</span><span class="n">bottomSheetState</span><span class="p">.</span><span class="n">expand</span><span class="p">()</span>
</code></pre></div></div>
<p>directly without being in a coroutine. Otherwise, the project won’t even compile and you would see the error:</p>
<blockquote>
<p>Suspend function ‘collapse’ should be called only from a coroutine or another suspend function</p>
</blockquote>
<p>Also, along with this release, you no longer had the possibility to set a callback in the expand function that would be executed after the animation has ended.</p>
<p>At the time I noticed that the solution for this was quite easy, I just needed to call the expand() or collapse() inside of a coroutine, and after looking online the approach that most people were following was:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">GlobalScope</span><span class="p">.</span><span class="n">launch</span> <span class="p">{</span>
<span class="n">bottomSheetScaffoldState</span><span class="p">.</span><span class="n">bottomSheetState</span><span class="p">.</span><span class="n">collapse</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<p>After making this change everything was working fine and I didn’t think twice about this solution… well, until beta 03.</p>
<h3 id="updating-to-beta03">Updating to beta03</h3>
<p>Now after updating to <strong>beta 03</strong>, calling expand() or collapse() within GlobalScope.launch my application started to crash with the error:</p>
<blockquote>
<p>A MonotonicFrameClock is not available in this CoroutineContext. Callers should supply an appropriate MonotonicFrameClock using withContext.</p>
</blockquote>
<p>This happens because <code class="highlighter-rouge">GlobalScope</code> doesn’t have a <code class="highlighter-rouge">CoroutineContext</code> associated with it, which is needed for animating the <strong>BottomSheet</strong>. Alternatively, we should use the CoroutineScope:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">val</span> <span class="py">coroutineScope</span> <span class="p">=</span> <span class="n">rememberCoroutineScope</span><span class="p">()</span>
<span class="kd">val</span> <span class="py">bottomSheetScaffoldState</span> <span class="p">=</span> <span class="n">rememberBottomSheetScaffoldState</span><span class="p">(</span>
<span class="n">bottomSheetState</span> <span class="p">=</span> <span class="n">rememberBottomSheetState</span><span class="p">(</span>
<span class="n">initialValue</span> <span class="p">=</span> <span class="n">BottomSheetValue</span><span class="p">.</span><span class="n">Collapsed</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">BottomSheetScaffold</span><span class="p">(</span>
<span class="n">sheetContent</span> <span class="p">=</span> <span class="p">{</span>
<span class="c1">// The content you want to show in your bottom sheet*</span>
<span class="p">},</span>
<span class="n">scaffoldState</span> <span class="p">=</span> <span class="n">bottomSheetScaffoldState</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// The content you want to show in your screen*</span>
<span class="p">}</span>
<span class="p">)</span>
</code></pre></div></div>
<p>And then when you want to <code class="highlighter-rouge">expand()</code> or <code class="highlighter-rouge">collapse()</code> the <strong>BottomSheet</strong>, call:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">coroutineScope</span><span class="p">.</span><span class="n">launch</span> <span class="p">{</span>
<span class="n">bottomSheetScaffoldState</span><span class="p">.</span><span class="n">bottomSheetState</span><span class="p">.</span><span class="n">collapse</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Moreover, using a GlobalScope usually, it’s not the best approach how there:</p>
<ul>
<li>The scope of GlobalScope corresponds to the app lifecycle.</li>
<li>It has no associated Job it’s not possible to cancel this coroutine.</li>
<li>Building tests for code that’s using GlobalScope is much trickier.</li>
</ul>
<p>And well, the official <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html">documentation</a> advise you not to use it:</p>
<blockquote>
<p>Application code usually should use an application-defined <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html">CoroutineScope</a>. Using <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html">async</a> or <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html">launch</a> on the instance of <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html">GlobalScope</a> is highly discouraged.</p>
</blockquote>
<h3 id="example">Example</h3>
<p>If you are looking for an example of a <strong>BottomSheetScaffold</strong> implemented, feel free to take a look at my submission for the #AndroidDevChallenge week #4:</p>
<ul>
<li><a href="https://github.com/cmota/wwweather">https://github.com/cmota/wwweather</a></li>
</ul>
<figure>
<img src="https://cdn-images-1.medium.com/max/2400/1*3y2F_Eu0sn_LRvNIZrNMqg.png" alt="wwweather application" />
<figcaption>wwweather application</figcaption>
</figure>
<p>Do you have a better approach? Something didn’t quite work with you?</p>
<p>Feel free to reply here or send me a message directly on <a href="https://twitter.com/cafonsomota">Twitter</a> 🙂.</p>Carlos Motacafonsomota@gmail.comGetting your KMM project working with Android Gradle Plugin 7.0+2021-03-29T00:00:00+01:002021-03-29T00:00:00+01:00https://cafonsomota.xyz/getting-your-kmm-project-working-with-android-gradle-plugin-7.0<figure>
<img src="/getting-your-kmm-project-working-with-android-gradle-plugin-7.0/featured.jpeg" alt="Getting your KMM project working with Android Gradle Plugin 7.0+ cover" />
</figure>
<h1 id="getting-your-kmm-project-working-with-android-gradle-plugin-70">Getting your KMM project working with Android Gradle Plugin 7.0+</h1>
<p>Getting… your KMM project working with AGP 7.0+ (Android Gradle Plugin) cover image</p>
<p>I’m really enthusiastic about the future of (native) mobile development. In the past years, we’ve been watching a paradigm switch on how we should develop our screens. We no longer need to do them on XML or XIBs, and can finally embrace the potential of declarative UIs. On the Android side, we’ve got Jetpack Compose, and on iOS SwiftUI.</p>
<p>Although still in beta, if you want to take advantage of the latest versions of Jetpack Compose, you’ll need to install the canary version of Android Studio (Canary build), currently, we are with Android Studio Arctic Fox - 2020.3.1 Canary 12.</p>
<p>However, these changes require that you update your Android project to the latest version of AGP (Android Gradle Plugin) — at the time of this writing I’m with <strong>gradle:7.0.0-alpha12</strong></p>
<p>Of course, all major updates require some other changes along the way. So, let’s enumerate all the problems that I had and how I’ve solved them.</p>
<p><strong>Note:</strong> the commands written here were tested on a Mac with Big Sur. If you’ve you’re using a different Operating System, they may differ.</p>
<h2 id="select-the-right-version-of-java">Select the right version of Java</h2>
<p>Not all the versions are currently supported, so if you have an error similar to this one:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> Task :common-dto:linkDebugFrameworkIosArm64 FAILED
e: Compilation failed: /Users/carlosmota/.konan/kotlin-native-prebuilt-macos-1.4.31/konan/nativelib/6538169044806663713/libllvmstubs.dylib: dlopen<span class="o">(</span>/Users/carlosmota/.konan/kotlin-native-prebuilt-macos-1.4.31/konan/nativelib/6538169044806663713/libllvmstubs.dylib, 1<span class="o">)</span>: no suitable image found. Did find:
</code></pre></div></div>
<p>It’s time to move to <strong>AdoptOpenJDK 11.0.10</strong>.</p>
<h3 id="why-11010">Why 11.0.10?</h3>
<p>I’ve tried a couple of versions and this one seemed to be the most recent supported by Gradle, if you try to run for instance OpenJDK14 you’ll get a couple of errors while trying to compile your project.</p>
<h3 id="how-to-install">How to install?</h3>
<p>The easiest way is to install it via brew:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew tap AdoptOpenJDK/openjdk
brew <span class="nb">install</span> <span class="nt">--cask</span> adoptopenjdk11
</code></pre></div></div>
<p><strong>Note:</strong> You can find all the information on their GitHub <a href="https://github.com/AdoptOpenJDK/homebrew-openjdk">repository</a>.</p>
<h3 id="what-if-you-have-different-java-versions-installed">What if you have different Java versions installed?</h3>
<p>It’s possible to have more than one version installed, but only set one as default. Run:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>java <span class="nt">-version</span>
</code></pre></div></div>
<p>And confirm that the version that is printed is the one you’ve just installed. Otherwise, you might have compilation errors while trying to build your KMM project.</p>
<p>To see all the Java versions that you’ve got installed, run:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/libexec/java_home <span class="nt">-V</span>
</code></pre></div></div>
<p>In my case, this is my output:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Matching Java Virtual Machines <span class="o">(</span>3<span class="o">)</span>:
16 <span class="o">(</span>x86_64<span class="o">)</span> “Oracle Corporation” — “Java SE 16” /Library/Java/JavaVirtualMachines/jdk-16.jdk/Contents/Home
11.0.10 <span class="o">(</span>x86_64<span class="o">)</span> “AdoptOpenJDK” — “AdoptOpenJDK 11” /Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home
1.8.281.09 <span class="o">(</span>x86_64<span class="o">)</span> “Oracle Corporation” — “Java” /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home
</code></pre></div></div>
<p>Since I’m looking for <strong>AdoptOpenJDK</strong> <strong>11.0.10</strong>, I need to update my <strong>JAVA_HOME</strong> path, for that, I can call directly:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">JAVA_HOME</span><span class="o">=</span><span class="sb">`</span>/usr/libexec/java_home <span class="nt">-v</span> 11.0.10<span class="sb">`</span>
</code></pre></div></div>
<p>Now, if I run the command java -version once again I’ll get the new path:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openjdk version “11.0.10” 2021–01–19
OpenJDK Runtime Environment AdoptOpenJDK <span class="o">(</span>build 11.0.10+9<span class="o">)</span>
OpenJDK 64-Bit Server VM AdoptOpenJDK <span class="o">(</span>build 11.0.10+9, mixed mode<span class="o">)</span>
</code></pre></div></div>
<p><strong>Note:</strong> using export is just setting the JAVA_HOME for the current run.</p>
<h2 id="configuration-with-name-testapi-not-found">Configuration with name ‘testApi’ not found.</h2>
<p>If you’re working on a KMM (Kotlin Multiplatform Mobile) project, when updating to AGP7.0.0 you’ll probably get an error similar to this one:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Configuration with name <span class="s1">'testApi'</span> not found.
at org.gradle.api.internal.artifacts.configurations.DefaultConfigurationContainer.createNotFoundException<span class="o">(</span>DefaultConfigurationContainer.java:165<span class="o">)</span>
at org.gradle.api.internal.DefaultNamedDomainObjectCollection.getByName<span class="o">(</span>DefaultNamedDomainObjectCollection.java:333<span class="o">)</span>
at org.gradle.api.internal.artifacts.configurations.DefaultConfiguratio§nContainer.getByName<span class="o">(</span>DefaultConfigurationContainer.java:155<span class="o">)</span>
</code></pre></div></div>
<p>This seems to be an issue with Gradle itself and it’s already reported on <a href="https://youtrack.jetbrains.com/issue/KT-43944">KT-43944</a>. Fortunately, the fix is really simple and there are no side effects (at least that we know of). On you <strong>build.gradle.kts</strong> add:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>android <span class="o">{</span>
configurations <span class="o">{</span>
create<span class="o">(</span><span class="s2">"androidTestApi"</span><span class="o">)</span>
create<span class="o">(</span><span class="s2">"androidTestDebugApi"</span><span class="o">)</span>
create<span class="o">(</span><span class="s2">"androidTestReleaseApi"</span><span class="o">)</span>
create<span class="o">(</span><span class="s2">"testApi"</span><span class="o">)</span>
create<span class="o">(</span><span class="s2">"testDebugApi"</span><span class="o">)</span>
create<span class="o">(</span><span class="s2">"testReleaseApi"</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p><strong>Note:</strong> you need to add this configuration before the kotlin {} block. A special thanks to Martin Bonnin for adding the solution to the issue.</p>
<h2 id="missingxcodeexception">MissingXcodeException</h2>
<p>Another that you might find during this update is that although you’ve got Xcode installed and have been using it without any problem in your KMM (Kotlin Multiplatform Mobile) project, suddenly when you decide to make the update you start having:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MissingXcodeException: An error occurred during an xcrun execution. Make sure that Xcode and its <span class="nb">command </span>line tools are properly installed. at org.jetbrains.kotlin.konan.target.CurrentXcode
</code></pre></div></div>
<p>Yes. No idea, how and why this starts to happen, but fortunately the fix is quite direct. Just open Xcode and go to:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Preferences → Locations → Command Line Tools
</code></pre></div></div>
<p>Per default it seems that there’s no option selected, just pick one.</p>
<figure>
<img src="https://cdn-images-1.medium.com/max/3768/1*18kHJvENE1oE6yWz0RJMIw.png" alt="Select one of Command Line Tools options" />
<figcaption>Select one of Command Line Tools options</figcaption>
</figure>
<p>Do you have a better approach? Something didn’t quite work with you?</p>
<p>Feel free to reply here or send me a message directly on <a href="https://twitter.com/cafonsomota">Twitter</a> 🙂.</p>Carlos Motacafonsomota@gmail.comRay Wenderlich: Window Insets and Keyboard Animations Tutorial for Android 112020-12-01T23:00:00+00:002020-12-01T23:00:00+00:00https://cafonsomota.xyz/rw-window-insets-and-keyboard-animations-tutorial-for-android-11<p>This article is part of the <a href="https://www.raywenderlich.com/18393648-window-insets-and-keyboard-animations-tutorial-for-android-11">Android & Kotlin Tutorials on Ray Wenderlich</a>.</p>
<figure>
<img src="/rw-window-insets-and-keyboard-animations-tutorial-for-android-11/rw-window-insets-and-keyboard-animations-tutorial-for-android-11_preview.png" alt="Website preview" />
<figcaption>Preview of Window Insets and Keyboard Animations Tutorial for Android 11</figcaption>
</figure>Carlos Motacafonsomota@gmail.comThis article is part of the Android & Kotlin Tutorials on Ray Wenderlich.