Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

생산성을 높이는 Android SDK 배포 전략

생산성을 높이는 Android SDK 배포 전략

주최: NAVER
행사: 2025 Engineering Day
날짜: 2025-05-30
제목: 생산성을 높이는 Android SDK 배포 전략

Avatar for Yeojun Yoon

Yeojun Yoon

May 30, 2025
Tweet

More Decks by Yeojun Yoon

Other Decks in Technology

Transcript

  1. )0)%7)w38) xx )%896)7 • 7944368w 2(63-(ww8%6+)8 xx 9+w-<)7 • '36)zww*36w0%6+)w-2498

    xx *-<Œ'36)zww*36w0%6+)w-2498 xx xx *)%8zw7944368w 2(63-(ww8%6+)8 )1%28-'w )67-32-2+
  2. on: push: branches: - main name: Release SDK jobs: release:

    runs-on: ubuntu-latest steps: - name: Release please action uses: googleapis/release-please-action@v4 id: release with: token: ${{ secrets.RELEASE_PLEASE_TOKEN }} - name: Update guide repository if: steps.release.outputs.releases_created == 'true' env: json: ${{ toJSON(steps.release.outputs) }} run: | curl -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer <GITHUB-TOKEN>" \ https://api.github.com/repos/android-sdk/guide/dispatches \ -d '{"event_type":"release-pr","client_payload":{"release_outputs":${{json}}}'  )437-836= 6)0)%7)§40)%7)wӦԲwᤓᥧwḢᖶ 6)0)%7)§40)%7)wӦԲw›⓪w஦ᾪ⥦ (-74%8',w w›᧗w஦ᾪ⥦
  3. on: repository_dispatch: types: [release-pr] name: Create new release PR jobs:

    new-release-pr: runs-on: ubuntu-latest steps: - name: Update version run: | new_version=${{ github.event.client_payload.release_outputs.version }} version_path="config.toml" sed -i "s@version = \".*\"@version = \"${new_version}\"@g" "${version_path}" - name: Update release note run: | new_release_note=${{ github.event.client_payload.release_outputs.body }} release_note_path="docs/release_note.md" sed -i "1i ${new_release_note}"$'\n\n' "${release_note_path}" - name: Commit new release run: # . . . - name: Create new release PR run: # . . . 9-() )437-836= ›ଢᑑὶw6)0)%7)wᒺ› ›ଢᑑὶw',%2+)w03+wᔮ፮ :)6-732 ፮ῆḪw⚎⺎ 6)0)%7)w238)w࣪ởwὍw℺wᣳΆ - version = 8.3.0 + version = 8.4.0 '32*-+x8310 + ## 8.4.0 + + ### Features + + - support A + - support B + ## 8.3.0 6)0)%7)¨238)x1(
  4. on: push: branches: - main name: Release SDK jobs: release:

    runs-on: ubuntu-latest steps: - name: Release please action uses: googleapis/release-please-action@v4 id: release with: token: ${{ secrets.RELEASE_PLEASE_TOKEN }} - name: Update sample app repository if: steps.release.outputs.releases_created == 'true' env: json: ${{ toJSON(steps.release.outputs) }} run: | curl -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer <GITHUB-TOKEN>" \ https://api.github.com/repos/android-sdk/sample/dispatches \ -d '{"event_type":"release-pr","client_payload":{"release_outputs":${{json}}}'  )437-836=
  5. on: repository_dispatch: types: [release-pr] name: Create new release PR jobs:

    new-release-pr: runs-on: ubuntu-latest steps: - name: Update version catalog run: | new_version=${{ github.event.client_payload.release_outputs.version }} name="my-sdk" path="gradle/libs.versions.toml" sed -i "" "s@^${name} = \".*\"@${name} = \\"${new_version}\\"@" "${path}" - name: Build Test run: ./gradlew assembleDebug - name: Android Test run: ./gradlew connectedDebugAndroidTest - name: Commit new version catalog run: # . . . - name: Create new release PR run: # . . . %140)w 44 )437-836= )67-32w %8%03+w⭂ᾲwᩎ⁋ 9-0(wᑅw 2(63-(w)78wᩎ⶿ [versions] - my-sdk = 8.3.0 + my-sdk = 8.4.0 0-&7x:)67-327x8310
  6. ᑦⰢw6%(0)w 32:)28-32w09+-2wῇᥧⶎ٦ 6%(0)w 32:)28-32w09+-2wὺw⺒ởⶎḢwᑦⰢw8%7/wᆲwⶒwԩḆᥒwԶᇢ &9-0(§03+-'Š'32:)28-32 plugins { `kotlin-dsl` } group

    = "com.example.buildlogic" java { sourceCompatibility = VERSION_17 targetCompatibility = VERSION_17 } kotlin { compilerOptions { jvmTarget = JvmTarget.JVM_17 } } &9-0(§03+-'Š'32:)28-32Š&9-0(x+6%(0)x/87 pluginManagement { repositories { mavenCenteral() google() gradlePluginPortal() } includeBuild("build-logic") } 7)88-2+7x+6%(0)x/87
  7. ᑦⰢw6%(0)w 32:)28-32w09+-2wῇᥧⶎ٦ 6%(0)w 32:)28-32w09+-2wὺw⺒ởⶎḢwᑦⰢw8%7/wᆲwⶒwԩḆᥒwԶᇢ /* . . . */ dependencies

    { compileOnly("com.vanniktech:gradle-maven-publish-plugin") /* . . . */ } &9-0(§03+-'Š'32:)28-32Š&9-0(x+6%(0)x/87 ,8847zŠŠ+-8,9&x'31Š:%22-/8)',Š+6%(0)§1%:)2§49&0-7,§409+-2 class PublishConventionPlugin : Plugin<Project> { override fun apply(target: Project) { with(target) { apply<MavenPublishBasePlugin>() configure<MavenPublishBaseExtension> { group = project.groupId version = project.versionName publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) signAllPublications() pomFromGradleProperties() } } } } &9-0(§03+-'Š'32:)28-32Š…Š9&0-7, 32:)28-3209+-2x/8
  8. ᑦⰢw6%(0)w 32:)28-32w09+-2wῇᥧⶎ٦ 6%(0)w 32:)28-32w09+-2wὺw⺒ởⶎḢwᑦⰢw8%7/wᆲwⶒwԩḆᥒwԶᇢ class PublishConventionPlugin : Plugin<Project> { override

    fun apply(target: Project) { with(target) { apply<MavenPublishBasePlugin>() configure<MavenPublishBaseExtension> { group = project.groupId version = project.versionName publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) publishToJFrogArtifactory() signAllPublications() pomFromGradleProperties() } } } } &9-0(§03+-'Š'32:)28-32Š…Š9&0-7, 32:)28-3209+-2x/8 private fun Project.publishToJFrogArtifactory() { extensions.getByType<PublishingExtension>() .repositories.maven { name = "jFrogArtifactory" url = uri("https://example.com/artifactory") with(project) { if (hasProperty("jFrogUsername") && hasProperty("jFrogPassword") ) { credentials { username = property("jFrogUsername").toString() password = property("jFrogPassword").toString() } } } } } &9-0(§03+-'Š'32:)28-32Š…Š9&0-7, 32:)28-3209+-2x/8
  9. ᑦⰢw6%(0)w 32:)28-32w09+-2wῇᥧⶎ٦ 6%(0)w 32:)28-32w09+-2wὺw⺒ởⶎḢwᑦⰢw8%7/wᆲwⶒwԩḆᥒwԶᇢ open class PublishConventionExtension @Inject constructor( objectFactory:

    ObjectFactory ) { @Input val publishType: Property<PublishType> = objectFactory .property<PublishType>() .convention(PublishType.ALL) // default value @Input val publishJavadoc: Property<Boolean> = objectFactory .property<Boolean>() .convention(false) // default value } enum class PublishType { ALL, INTERNAL_ONLY, EXTERNAL_ONLY } &9-0(§03+-'Š'32:)28-32Š…Š9&0-7, 32:)28-32<8)27-32x/8 class PublishConventionPlugin : Plugin<Project> { override fun apply(target: Project) { with(target) { apply<MavenPublishBasePlugin>() configure<MavenPublishBaseExtension> { /* . . . */ val extension = extensions .create<PublishConventionExtension>( name = "publishOptions" ) configurePublishing(extension) } } } } &9-0(§03+-'Š'32:)28-32Š…Š9&0-7, 32:)28-3209+-2x/8 publishOptions { publishType = INTERNAL_ONLY publishJavadoc = true }
  10. ᑦⰢw6%(0)w 32:)28-32w09+-2wῇᥧⶎ٦ 6%(0)w 32:)28-32w09+-2wὺw⺒ởⶎḢwᑦⰢw8%7/wᆲwⶒwԩḆᥒwԶᇢ internal fun Project.configurePublishing(extension: PublishConventionExtension) { afterEvaluate

    { if (extension.publishJavadoc.get()) { apply<DokkaConventionPlugin>() } extensions.configure<PublishingExtension> { publications { val publishType = extension.publishType.get() if (publishType == PublishType.ALL || publishType == PublishType.INTERNAL_ONLY) { createMavenPublication(project = project, flavor = "internal") } if (publishType == PublishType.ALL || publishType == PublishType.EXTERNAL_ONLY) { createMavenPublication(project = project, flavor = "external") } } tasks.withType<PublishToMavenRepository>().matching { task -> val (repositoryName, publicationName) = with(task) { repository.name to publication.name } repositoryName == "jFrogArtifactory" && publicationName.startWith("external") || repositoryName == "mavenCentral" && publicationName.startWith("internal") }.configureEach { enabled = false } } } &9-0(§03+-'Š'32:)28-32Š…Š9&0-7, 32*-+x/8 49&0-7,=4) ᓺwᑦⰢwṫᦎwᖺ٦ ዞ೾wᓺw.%:%(3' ᑦⰢwḢᖶwᖺ٦ *0%:36wᓺwᑦⰢw‶Ίᧂwᖺ٦
  11. ᑦⰢw6%(0)w 32:)28-32w09+-2wῇᥧⶎ٦ 6%(0)w 32:)28-32w09+-2wὺw⺒ởⶎḢwᑦⰢw8%7/wᆲwⶒwԩḆᥒwԶᇢ private fun PublisherContainer.createMavenPublication(project: Project, flavor: String)

    { create<MavenPublication>(flavor) { if (flavor == "internal") { project.extensions.findByType<LibraryExtension>()?.let { android -> artifact( project.tasks.create<Jar>("androidInternalSourcesJar") { archiveClassifier.set("sources") archiveFileName.set("internal-sources.jar") from( android.sourcesSets.getByName("main").java.srcDirs android.sourcesSets.getByName("internal").java.srcDirs ) } ) } } if (flavor == "external") { pom.license { /* . . . */ } } artifactId = project.artifactId + flavor /* . . . */ } &9-0(§03+-'Š'32:)28-32Š…Š9&0-7, 32*-+x/8 )<8)62%0wởw431wᥚ⁋ -28)62%0wởw7396')7%6 ᑦⰢ %68-*%'8( Ḇ *0%:36wᣳΆ
  12. ᑦⰢw6%(0)w 32:)28-32w09+-2wῇᥧⶎ٦ 6%(0)w 32:)28-32w09+-2wὺw⺒ởⶎḢwᑦⰢw8%7/wᆲwⶒwԩḆᥒwԶᇢ plugins { `kotlin-dsl` } /* .

    . . */ gradlePlugin { plugins { register("examplePublish") { id = "example.convention.publish" implementationClass = "PublishConventionPlugin" } } } &9-0(§03+-'Š'32:)28-32Š&9-0(x+6%(0)x/87 plugins { id("example.convention.publish") /* . . . */ } publishOptions { publishType = PublishType.ALL publishJavadoc = false } /* . . . */ *)%896)Š,31)Š&9-0(x+6%(0)x/87 plugins { id("example.convention.publish") /* . . . */ } publishOptions { publishType = PublishType.INTERNAL_ONLY publishJavadoc = true } /* . . . */ *)%896)Š&-00-2+Š&9-0(x+6%(0)x/87
  13. ᑦⰢwᾪ⻺wԫὖwⴺ႒᥮᫚wῆఏ⺊ ᑦⰢwᾪ⻺ Զၞwሚ⓪wᑅw w᫢࿏w⑺ॆwᶂᇲ ᣢ࣪wᚂഒw‶Ίᧂw᷻႒ഒ (3//%w፮ᥒ ᚂഒ ሚ⓪w0%'/w⑺ॆwᶂᇲ 690)6wᖺᥓwᇢⰢ⫮ https://github.com/naver/nam-sdk-android/releases.tag/v8.4.1

    https://naver.github.io/nam-sdk-android https://naver.github.io/nam-sdk-guide/android https://사내빌드저장소.com/app/android/gfp-sdk/real/latest https://사내빌드저장소.com/app/android/gfp-sdk/real  w⑺ॆᾲwᬒwᤎⵂᶧwᇷ⢢w›ଢ