Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Create an Android plugin using Kotlin

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →

Create an Android plugin using Kotlin

Presentation @Google Developers Group Lisbon
27/09/2016

Avatar for Bruno Oliveira

Bruno Oliveira

September 24, 2016

More Decks by Bruno Oliveira

Other Decks in Programming

Transcript

  1. Build a Gradle plugin using Kotlin • Why Kotlin •

    Localizable.io • Android specific plugin • Build the plugin step-by-step
  2. Why do we need a plugin? • Build (me analyse

    android resources • Parse generated values folders • Extract Strings • Manifest • Make a seamless experience
  3. What/How are we doing with it? • Extract strings from

    values • Cache and send to server • Try to automate as much as possible
  4. Biggest problems at start • Android studio • Trying to

    implement the sample right in the same project • Deploy development dependency to local maven repo
  5. Setup dependencies aka build.gradle • Kotlin • GradleApi • Build

    Tools apply plugin: "kotlin" dependencies { compile gradleApi() compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.3" compile "com.android.tools.build:gradle:2.1.3" }
  6. Declare a plugin • Plugin class class LocalizablePlugin : Plugin<Project>

    { override fun apply(project: Project?) { project?.let { ProjectHandler(it).createTasks() } } }
  7. Declare a plugin • Use the plugin apply plugin: 'localizable'

    buildscript { dependencies { classpath "io.localizable:sync:1.0.4-SNAPSHOT" } }
  8. When tasks added fun createTasks() { if (!isAndroidProject) { throw

    Throwable("You should apply android to your project first") } tasks.whenTaskAdded { handleTask(it) } }
  9. Android build tools check private val isAndroidProject: Boolean by lazy

    { project.plugins.hasPlugin(AppPlugin::class.java) } private val appExtension: AppExtension by lazy { project.extensions.getByType(AppExtension::class.java) } private val flavorNames: List<String> by lazy { val configs = appExtension.productFlavors.map { it.name } if (configs.isNotEmpty()) configs else listOf("") } private val buildTypes: Collection<BuildType> by lazy { appExtension.buildTypes }
  10. Handle everything • We don't wanna miss a thing. private

    fun handleTask(task: Task) { buildTypes.forEach { build -> flavorNames.forEach { flavor -> processBuild(build.name, flavor, task) } } }
  11. Find the One private fun processBuild(buildName: String, flavorName: String, task:

    Task) { val taskAffix = LocalizableHelper.taskAffix(buildName, flavorName) val processTask = "process${taskAffix}Resources" if (processTask.equals(task.name)) { createLocalizableFromTask(task, taskAffix, buildName, flavorName) } }
  12. Execute • Execute block • Follow the behaviors • Use

    the build cache folders if needed nTask.doFirst { val manifest = LocalizableHelper.manifestFileForTarget(project, buildName, flavorName) if (manifest == null) { println("Could not find any manifest file") return@doFirst } nTask.didWork = LocalizableTask(project, manifest, localizableTaskName).syncResources() }
  13. Add task to Android stack • Task in the middle

    • mergeDebugEpicResources > localizableEpicResources > ProcessDebugEpicResources task.dependsOn(nTask) val mergeTask = "merge${taskAffix}Resources" project.tasks.getByName(localizableTaskName).dependsOn(mergeTask)
  14. Deploy locally Run the task - Command line ./gradlew :plugin:uploadArchives

    uploadArchives { repositories { mavenDeployer { repository(url: mavenLocal().url) pom.groupId = GROUP_ID pom.artifactId = ARTIFACT_PLUGIN_ID pom.version = PLUGIN_VERSION } } }
  15. Debug :( • Network interceptor private val interceptor: HttpLoggingInterceptor by

    lazy { val interceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { println(" -> $it") }) interceptor.level = HttpLoggingInterceptor.Level.BODY interceptor }