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

Your Android Open Source Library

7c53eb20018778f6ff2670ea378ad2da?s=47 Sangsoo Nam
September 04, 2017

Your Android Open Source Library

Open source libraries make the development much easier. You don't have to spend your time for making similar things. If you cannot find what you want, now it's time to make it and release to everyone.

In this talk, I explain how to make an open source library including hosting, testing, continuous integration, and publishing for both types: jar(java) and aar(android)

7c53eb20018778f6ff2670ea378ad2da?s=128

Sangsoo Nam

September 04, 2017
Tweet

Transcript

  1. Your Android 
 Open Source Library Think, Build, Ship and

    Tweak Sangsoo Nam sangsoo@spotify.com
  2. Sangsoo Nam Senior Android Engineer at Spotify sangsoonam.github.io @sangsoonam

  3. Open Source

  4. Open Source Show your work

  5. Open Source Show your work Teach others

  6. Open Source Show your work Teach others Lower bugs

  7. Open Source Show your work Teach others Lower bugs Upstream

    improvement
  8. Open Source Show your work Teach others Lower bugs Great

    advertising Upstream improvement
  9. Open Source Show your work Teach others Lower bugs It’s

    fun! Great advertising Upstream improvement
  10. https:/ /spotify.github.io/

  11. https:/ /spotify.github.io/

  12. https:/ /spotify.github.io/

  13. 6

  14. Open Source Library

  15. Open Source Library Dagger2

  16. Open Source Library Dagger2 Picasso

  17. Open Source Library Dagger2 Picasso RxJava

  18. Open Source Library Dagger2 Picasso RxJava OkHttp

  19. Open Source Library Dagger2 Picasso RxJava OkHttp Guava

  20. Open Source Library Dagger2 Picasso RxJava AutoValue OkHttp Guava

  21. Open Source Library Dagger2 Picasso RxJava AutoValue OkHttp Guava compile

    ‘xxx:xxx:0.1.0’
  22. Java Library

  23. Think Build Ship

  24. None
  25. { "items": [ ... { "uri": "spotify:track:7MHN1aCFtLXjownGhvEQlF", "attributes": { "format_attributes":

    [ { "key": "status", "value": "UP" }, ... ] } }, { "uri": "spotify:track:7nKBxz47S9SD79N086fuhn", "attributes": { "format_attributes": [ { "key": "status", "value": "DOWN" }, ... ] } }, { "uri": "spotify:track:3rOSwuTsUlJp0Pu0MkN8r8", "attributes": { "format_attributes": [ { "key": "status", "value": "EQUAL" }, ... ] ≈ ≈ ≈
  26. if ("UP".equals(status)) { showIcon(iconUp); } else if("DOWN".equals(status)) { showIcon(iconDown); }

    else if("EQUAL".equals(status)) { showIcon(iconEqual); }
  27. if ("UP".equals(status)) { showIcon(iconUp); } else if("DOWN".equals(status)) { showIcon(iconDown); }

    else if("EQUAL".equals(status)) { showIcon(iconEqual); } • Every time string comparison with “equals” method • Typo error (e.g Upper or lower case)
  28. if (Status.UP == status) { showIcon(iconUp); } else if(Status.DOWN ==

    status) { showIcon(iconDown); } else if(Status.EQUAL == status) { showIcon(iconEqual); } • No need to compare strings
  29. Think Avoid comparing strings every time 
 for JSON data

    Build Ship
  30. Ignore Case "UP" "DOWN" "EQUAL" Status.UP Status.DOWN Status.EQUAL "Up" "up"

    "DoWn" "down" “equaL"
  31. Edge Cases "ALIEN" return null throw new EnumConstantNotPresentException()

  32. Edge Cases "ALIEN" return null throw new EnumConstantNotPresentException() "SHUFFLE-PLAY" Mode.SHUFFLE_PLAY

    • Enum doesn’t allow “_” • Support conversion
  33. None
  34. None
  35. None
  36. None
  37. None
  38. None
  39. None
  40. None
  41. None
  42. None
  43. EnumParser public enum Status { UP, DOWN, EQUAL; } @Test

    public void testEnumParser() { assertThat(EnumParser.forClass(Status.class).parse("UP")).isSameAs(Status.UP); assertThat(EnumParser.forClass(Status.class).parse("up")).isSameAs(Status.UP); assertThat(EnumParser.forClass(Status.class).parse("uP")).isSameAs(Status.UP); assertThat(EnumParser.forClass(Status.class).parse("DOWN")).isSameAs(Status.DOWN); assertThat(EnumParser.forClass(Status.class).parse("EQUAL")).isSameAs(Status.EQUAL); }
  44. EnumParser @Test public void testEnumParser() { assertThat(EnumParser.forClass(Status.class).parse("ALIEN")).isNull(); } @Test(expected =

    EnumConstantNotPresentException.class) public void testEnumParserStrict() { EnumParser.forClass(Status.class).parseStrict("ALIEN") } @Test public void testEnumParserVariation() { EnumParser<Mode> enumParser = EnumParser.forClass(Mode.class).withVariation( (mode) -> mode.name().replaceAll("_", "-") ); assertThat(enumParser.parse("SHUFFLE_PLAY")).isSameAs(Mode.SHUFFLE_PLAY); assertThat(enumParser.parse("SHUFFLE-PLAY")).isSameAs(Mode.SHUFFLE_PLAY); }
  45. EnumParser @Test public void testEnumParser() { assertThat(EnumParser.forClass(Status.class).parse("ALIEN")).isNull(); } @Test(expected =

    EnumConstantNotPresentException.class) public void testEnumParserStrict() { EnumParser.forClass(Status.class).parseStrict("ALIEN") } @Test public void testEnumParserVariation() { EnumParser<Mode> enumParser = EnumParser.forClass(Mode.class).withVariation( (mode) -> mode.name().replaceAll("_", "-") ); assertThat(enumParser.parse("SHUFFLE_PLAY")).isSameAs(Mode.SHUFFLE_PLAY); assertThat(enumParser.parse("SHUFFLE-PLAY")).isSameAs(Mode.SHUFFLE_PLAY); }
  46. Think Avoid comparing strings every time 
 for JSON data

    Build EnumParser: 
 Case insensitive parser 
 from string to Enum Ship
  47. Open Source Library

  48. Open Source Library

  49. None
  50. None
  51. None
  52. None
  53. None
  54. “Is this open source project?”

  55. Licenses Exclusive copyright by default. Have to say what others

    can do with it.
  56. MIT Apache 2.0 GPLv3 Permissions • Commercial use • Distribution

    • Modification • Private use • Commercial use • Distribution • Modification • Private use • Patent use • Commercial use • Distribution • Modification • Private use • Patent use Conditions • License and copyright notice • License and copyright notice • State changes • License and copyright notice • State changes • Disclose source • Same license Limitations • Liability • Warranty • Liability • Warranty • Trademark use • Liability • Warranty Weaker Stronger https:/ /choosealicense.com/licenses/
  57. None
  58. None
  59. None
  60. None
  61. Document What is this project? How to use it? Is

    it open source? Which license? How can I contribute?
  62. https:/ /www.udacity.com/course/writing-readmes--ud777

  63. None
  64. None
  65. CI Badges Make sure every thing works after any change.

    Show your project is stable and well tested.
  66. Build Status

  67. None
  68. None
  69. None
  70. .travis.yml language: java

  71. None
  72. None
  73. None
  74. None
  75. Test Coverage

  76. https:/ /coveralls.io/

  77. None
  78. build.gradle plugins { id 'jacoco' id 'com.github.kt3k.coveralls' version '2.8.1' }

    … jacocoTestReport { reports { xml.enabled = true // coveralls plugin depends on xml format report html.enabled = true } }
  79. .travis.yml language: java after_success: - ./gradlew test jacocoTestReport coveralls

  80. None
  81. None
  82. None
  83. None
  84. Open Source Library

  85. Open Source Library

  86. compile 'com.google.dagger:dagger:2.11' compile 'com.squareup.picasso:picasso:2.5.2' compile 'com.squareup.okhttp3:okhttp:3.8.1'

  87. Library Repository Icons made by Freepik from www.flaticon.com is licensed

    by CC 3.0 BY
  88. Library Repository compile ’xxx:xxx:0.1.0’ Icons made by Freepik from www.flaticon.com

    is licensed by CC 3.0 BY
  89. Library Repository compile ’xxx:xxx:0.1.0’ Icons made by Freepik from www.flaticon.com

    is licensed by CC 3.0 BY
  90. Library Repository compile ’xxx:xxx:0.1.0’ JFrog Bintray 
 jcenter Icons made

    by Freepik from www.flaticon.com is licensed by CC 3.0 BY
  91. Library Repository compile ’xxx:xxx:0.1.0’ Sonatype
 Maven Central JFrog Bintray 


    jcenter Icons made by Freepik from www.flaticon.com is licensed by CC 3.0 BY
  92. Library Repository compile ’xxx:xxx:0.1.0’ Sonatype
 Maven Central JFrog Bintray 


    jcenter Icons made by Freepik from www.flaticon.com is licensed by CC 3.0 BY
  93. jcenter Maven repository hosted by JFrog Bintray. Deliver library though

    CDN. Largest Java Repository. Support easy way to upload
 Maven Central
  94. https:/ /bintray.com

  95. None
  96. None
  97. None
  98. None
  99. Maven A project management and comprehension tool providing a way

    to help with managing: • Builds • Dependencies • Releases • Distributions
 group_id:artifact_id:version POM(Project Object Model) file describes the project. 'com.google.dagger:dagger:2.11'
  100. build.gralde apply plugin: 'maven-publish' ... ext { PUBLISH_GROUP_ID = 'io.github.sangsoonam'

    PUBLISH_VERSION = '0.1.0' } 
 publishing { publications { MyPublication(MavenPublication) { from components.java groupId = PUBLISH_GROUP_ID version = PUBLISH_VERSION } } }
  101. Command ~/enumparser> ./gradlew publishToMavenLocal :enumparser:generatePomFileForMyPublicationPublication :enumparser:compileJava UP-TO-DATE :enumparser:processResources UP-TO-DATE :enumparser:classes

    UP-TO-DATE :enumparser:jar :enumparser:publishMyPublicationPublicationToMavenLocal :enumparser:publishToMavenLocal BUILD SUCCESSFUL Total time: 5.307 secs ~/enumparser> ls -al ~/.m2/repository/io/github/sangsoonam/enumparser/0.1.0 total 16 drwxr-xr-x 4 sangsoo staff 136 Aug 8 21:36 . drwxr-xr-x 5 sangsoo staff 170 Aug 8 21:36 .. -rw-r--r-- 1 sangsoo staff 2174 Aug 8 21:37 enumparser-0.1.0.jar -rw-r--r-- 1 sangsoo staff 613 Aug 8 21:37 enumparser-0.1.0.pom
  102. pom.xml ~/enumparser> cat ~/.m2/repository/io/github/sangsoonam/enumparser/0.1.0/enumparser-0.1.0.pom <?xml version="1.0" encoding="UTF-8"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/

    maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>io.github.sangsoonam</groupId> <artifactId>enumparser</artifactId> <version>0.1.0</version> <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>11.0.1</version> <scope>runtime</scope> </dependency> </dependencies> </project>
  103. None
  104. None
  105. Don’t release it manually!

  106. build.gralde plugins { id "com.jfrog.bintray" version "1.7" } ... bintray

    { user = System.getenv('BINTRAY_USER') key = System.getenv('BINTRAY_API_KEY') publications = ['MyPublication'] publish = true pkg { repo = PUBLISH_ARTIFACT_ID name = PUBLISH_ARTIFACT_ID version { name = 'v' + PUBLISH_VERSION released = new Date() } } }
  107. Command ~/enumparser> ./gradlew bintrayUpload :enumparser:generatePomFileForMyPublicationPublication :enumparser:compileJava UP-TO-DATE :enumparser:processResources UP-TO-DATE :enumparser:classes

    UP-TO-DATE :enumparser:jar UP-TO-DATE :enumparser:javadoc UP-TO-DATE :enumparser:javadocJar UP-TO-DATE :enumparser:sourceJar UP-TO-DATE :enumparser:publishMyPublicationPublicationToMavenLocal :enumparser:bintrayUpload BUILD SUCCESSFUL Total time: 6.62 secs
  108. None
  109. None
  110. None
  111. build.gralde repositories { maven { url "http://dl.bintray.com/sangsoonam/enumparser" }
 jcenter() }

    dependencies { compile 'io.github.sangsoonam:enumparser:0.1.0' }
  112. Artifact Repository

  113. Artifact Repository Maven Release .jar + pom.xml JFrog Bintray 


    jcenter
  114. Artifact Repository Maven Release .jar + pom.xml JFrog Bintray 


    jcenter Your Bintray Upload
  115. Artifact Repository Maven Release .jar + pom.xml JFrog Bintray 


    jcenter Your Bintray Upload Sync
  116. None
  117. None
  118. None
  119. None
  120. !

  121. Maven Central Maven repository hosted by Sonatype. Well known. Quite

    hard to start but 
 have good guidelines for releasing.
  122. https:/ /issues.sonatype.org/

  123. https:/ /issues.sonatype.org/

  124. https:/ /issues.sonatype.org/

  125. None
  126. Artifact Repository Maven Release .jar + pom.xml JFrog Bintray 


    jcenter Your Bintray Upload Sync
  127. Artifact Repository Maven Release .jar + pom.xml JFrog Bintray 


    jcenter Your Bintray Upload Sync Sonatype
 Maven Central Sync
  128. None
  129. None
  130. Maven Central Requirements Have source and javadoc artifacts. POM(Project Object

    Model) should have enough information for the project. • Project Name • Project Description • Project URL • License • SCM URL • Developer information Artifacts should be signed for validation.
  131. pom.xml ~/enumparser> cat ~/.m2/repository/io/github/sangsoonam/enumparser/0.1.0/enumparser-0.1.0.pom <?xml version="1.0" encoding="UTF-8"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/

    maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>io.github.sangsoonam</groupId> <artifactId>enumparser</artifactId> <version>0.1.0</version> <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>11.0.1</version> <scope>runtime</scope> </dependency> </dependencies> </project>
  132. build.gradle task javadocJar (type: Jar, dependsOn: javadoc) { classifier "sources"

    from javadoc.destinationDir } task sourceJar(type: Jar) { classifier "javadoc" from sourceSets.main.allJava } publishing { publications { MyPublication(MavenPublication) { from components.java groupId = PUBLISH_GROUP_ID version = PUBLISH_VERSION artifact sourceJar artifact javadocJar } } }
  133. build.gradle task javadocJar (type: Jar, dependsOn: javadoc) { classifier "sources"

    from javadoc.destinationDir } task sourceJar(type: Jar) { classifier "javadoc" from sourceSets.main.allJava } publishing { publications { MyPublication(MavenPublication) { from components.java groupId = PUBLISH_GROUP_ID version = PUBLISH_VERSION artifact sourceJar artifact javadocJar } } } ≈
  134. build.gradle publishing { publications { MyPublication(MavenPublication) { from components.java groupId

    = PUBLISH_GROUP_ID version = PUBLISH_VERSION artifact sourceJar artifact javadocJar pom.withXml { asNode().children().last() + pomConfig } } } }
  135. build.gradle publishing { publications { MyPublication(MavenPublication) { from components.java groupId

    = PUBLISH_GROUP_ID version = PUBLISH_VERSION artifact sourceJar artifact javadocJar pom.withXml { asNode().children().last() + pomConfig } } } } ≈
  136. build.gradle publishing { publications { MyPublication(MavenPublication) { from components.java groupId

    = PUBLISH_GROUP_ID version = PUBLISH_VERSION artifact sourceJar artifact javadocJar pom.withXml { asNode().children().last() + pomConfig } } } } ≈ def pomConfig = { description(PUBLISH_DESCRIPTION){} name PUBLISH_ARTIFACT_ID url GITHUB_URL licenses { license { name 'MIT License' url ‘http://www.opensource.org/...' } } scm { url GITHUB_URL } developers { developer { name DEVELOPER_NAME } } }
  137. pom.xml ~/enumparser> cat ~/.m2/repository/io/github/sangsoonam/enumparser/0.1.0/enumparser-0.1.0.pom <?xml version="1.0" encoding="UTF-8"?> ... <description>Utility for

    parsing a string to Enum constant.</description> <name>enumparser</name> <url>https://github.com/SangsooNam/enumparser</url> <licenses> <license> <name>MIT License</name> <url>http://www.opensource.org/licenses/mit-license.php</url> </license> </licenses> <scm> <url>https://github.com/SangsooNam/enumparser</url> </scm> <developers> <developer> <name>Sangsoo Nam</name> </developer> </developers> </project>
  138. None
  139. None
  140. None
  141. Don’t release it manually!

  142. Don’t release it manually!

  143. build.gralde plugins { id "com.jfrog.bintray" version "1.7" } bintray {

    user = System.getenv('BINTRAY_USER') key = System.getenv('BINTRAY_API_KEY') publications = ['MyPublication'] publish = true pkg { repo = PUBLISH_ARTIFACT_ID name = PUBLISH_ARTIFACT_ID version { name = 'v' + PUBLISH_VERSION released = new Date() mavenCentralSync { user = System.getenv('OSS_USER') password = System.getenv('OSS_PASSWORD') } } } }
  144. build.gralde plugins { id "com.jfrog.bintray" version "1.7" } bintray {

    user = System.getenv('BINTRAY_USER') key = System.getenv('BINTRAY_API_KEY') publications = ['MyPublication'] publish = true pkg { repo = PUBLISH_ARTIFACT_ID name = PUBLISH_ARTIFACT_ID version { name = 'v' + PUBLISH_VERSION released = new Date() mavenCentralSync { user = System.getenv('OSS_USER') password = System.getenv('OSS_PASSWORD') } } } } ≈
  145. Command ~/enumparser> ./gradlew bintrayUpload :enumparser:generatePomFileForMyPublicationPublication :enumparser:compileJava UP-TO-DATE :enumparser:processResources UP-TO-DATE :enumparser:classes

    UP-TO-DATE :enumparser:jar UP-TO-DATE :enumparser:javadoc UP-TO-DATE :enumparser:javadocJar UP-TO-DATE :enumparser:sourceJar UP-TO-DATE :enumparser:publishMyPublicationPublicationToMavenLocal :enumparser:bintrayUpload BUILD SUCCESSFUL Total time: 6.62 secs
  146. None
  147. “jcenter should be enough to release, but good to follow

    
 Maven Central requirements”
  148. Android Library

  149. AAR Android Archive Library. Includes resources such as layouts, drawables,

    strings and etc.

  150. Think Build Ship

  151. Duotone Image A half-tone illustration made from a single original

    image with two different colours.
  152. Duotone Image A half-tone illustration made from a single original

    image with two different colours.
  153. Build Ship Think Convert images as a duotone

  154. None
  155. None
  156. None
  157. None
  158. None
  159. None
  160. None
  161. None
  162. None
  163. None
  164. None
  165. Sample Code

  166. None
  167. None
  168. None
  169. None
  170. None
  171. None
  172. None
  173. None
  174. Build DuotoneImageView:
 Custom ImageView for Android Ship Think Convert images

    as a duotone
  175. None
  176. None
  177. None
  178. CI Badges Make sure every thing works after any change.

    Show your project is stable and well tested.
  179. Build Status

  180. None
  181. .travis.yml language: android jdk: oraclejdk8 android: components: - tools -

    platform-tools - build-tools-25.0.1 - android-25 - extra-android-m2repository
  182. None
  183. None
  184. Test Coverage

  185. None
  186. build.gradle buildscript { dependencies { classpath 'com.dicedmelon.gradle:jacoco-android:0.1.1' } } plugins

    { id 'jacoco-android' id 'com.github.kt3k.coveralls' version '2.5.0-x' } android { ... testOptions { unitTests.all { jacoco { // To include Robolectric tests includeNoLocationClasses = true } } } } coveralls { jacocoReportPath = "${buildDir}/reports/jacoco/jacocoTestDebugUnitTestReport/jacocoTestDebugUnitTestReport.xml" }
  187. .travis.yml language: android ... after_success: - ./gradlew testDebugUnitTest jacocoTestReport coveralls

  188. None
  189. None
  190. Artifact Repository compile ’xxx:xxx:0.1.0’ Sonatype
 Maven Central JFrog Bintray 


    jcenter Icons made by Freepik from www.flaticon.com is licensed by CC 3.0 BY
  191. Artifact Repository compile ’xxx:xxx:0.1.0’ Sonatype
 Maven Central JFrog Bintray 


    jcenter Icons made by Freepik from www.flaticon.com is licensed by CC 3.0 BY
  192. None
  193. build.gralde apply plugin: 'maven-publish' ext { PUBLISH_GROUP_ID = 'io.github.sangsoonam' PUBLISH_VERSION

    = '0.1.1' } publishing { publications { MyPublication(MavenPublication) { groupId = PUBLISH_GROUP_ID version = PUBLISH_VERSION artifact "${project.buildDir}/outputs/aar/${project.name}-release.aar" } } } ≈
  194. Command ~/duotoneimageview> ./gradlew publishToMavenLocal :duotoneimageview:generatePomFileForMyPublicationPublication :duotoneimageview:javadoc :duotoneimageview:javadocJar :duotoneimageview:sourceJar :duotoneimageview:publishMyPublicationPublicationToMavenLocal :duotoneimageview:publishToMavenLocal

    BUILD SUCCESSFUL Total time: 7.791 secs ~/duotoneimageview> ls -al ~/.m2/repository/io/github/sangsoonam/duotoneimageview/0.1.0 total 96 drwxr-xr-x 6 sangsoo staff 204 Aug 9 09:51 . drwxr-xr-x 4 sangsoo staff 136 Aug 9 09:51 .. -rw-r--r-- 1 sangsoo staff 16749 Aug 9 08:43 duotoneimageview-0.1.0.aar -rw-r--r-- 1 sangsoo staff 925 Aug 9 09:51 duotoneimageview-0.1.0.pom
  195. None
  196. None
  197. build.gralde plugins { id "com.jfrog.bintray" version "1.7" } ... bintray

    { user = System.getenv('BINTRAY_USER') key = System.getenv('BINTRAY_API_KEY') publications = ['MyPublication'] publish = true pkg { repo = PUBLISH_ARTIFACT_ID name = PUBLISH_ARTIFACT_ID version { name = PUBLISH_VERSION released = new Date() } } }
  198. Command ~/duotoneimageview> ./gradlew bintrayUpload :duotoneimageview:generatePomFileForMyPublicationPublication :duotoneimageview:javadoc UP-TO-DATE :duotoneimageview:javadocJar UP-TO-DATE :duotoneimageview:sourceJar

    UP-TO-DATE :duotoneimageview:publishMyPublicationPublicationToMavenLocal :duotoneimageview:bintrayUpload BUILD SUCCESSFUL Total time: 9.842 secs
  199. None
  200. None
  201. Maven Central Requirements Have source and javadoc artifacts. POM(Project Object

    Model) should have enough information for the project. • Project Name • Project Description • Project URL • License • SCM URL • Developer information Artifacts should be signed for validation.
  202. build.gradle task sourceJar(type: Jar) { classifier = 'sources' from android.sourceSets.main.java.srcDirs

    } task javadoc(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from javadoc.destinationDir } publishing { publications { MyPublication(MavenPublication) { groupId = PUBLISH_GROUP_ID version = PUBLISH_VERSION artifact "${project.buildDir}/outputs/aar/${project.name}-release.aar" artifact sourceJar artifact javadocJar } } }
  203. build.gradle task sourceJar(type: Jar) { classifier = 'sources' from android.sourceSets.main.java.srcDirs

    } task javadoc(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from javadoc.destinationDir } publishing { publications { MyPublication(MavenPublication) { groupId = PUBLISH_GROUP_ID version = PUBLISH_VERSION artifact "${project.buildDir}/outputs/aar/${project.name}-release.aar" artifact sourceJar artifact javadocJar } } } ≈
  204. build.gradle publishing { publications { MyPublication(MavenPublication) { groupId = PUBLISH_GROUP_ID

    version = PUBLISH_VERSION ... artifact sourceJar artifact javadocJar pom.withXml { asNode().children().last() + pomConfig } } } } ≈ def pomConfig = { description(PUBLISH_DESCRIPTION){} name PUBLISH_ARTIFACT_ID url GITHUB_URL licenses { license { name 'MIT License' url ‘http://www.opensource.org/...' } } scm { url GITHUB_URL } developers { developer { name DEVELOPER_NAME } } }
  205. None
  206. build.gralde plugins { id "com.jfrog.bintray" version "1.7" } bintray {

    user = System.getenv('BINTRAY_USER') key = System.getenv('BINTRAY_API_KEY') publications = ['MyPublication'] publish = true pkg { repo = PUBLISH_ARTIFACT_ID name = PUBLISH_ARTIFACT_ID version { name = PUBLISH_VERSION released = new Date() mavenCentralSync { user = System.getenv('OSS_USER') password = System.getenv('OSS_PASSWORD') } } } } ≈
  207. Command ~/duotoneimageview> ./gradlew bintrayUpload :duotoneimageview:generatePomFileForMyPublicationPublication :duotoneimageview:javadoc UP-TO-DATE :duotoneimageview:javadocJar UP-TO-DATE :duotoneimageview:sourceJar

    UP-TO-DATE :duotoneimageview:publishMyPublicationPublicationToMavenLocal :duotoneimageview:bintrayUpload BUILD SUCCESSFUL Total time: 9.842 secs
  208. None
  209. None
  210. Summary • Your code is valuable for other developers. Open

    your code. • Don’t forget the license • Document, document and document. • Continuous Integration: building and unit testing. • Release your library: jcenter or Maven central • Tweak if you have requests or pull request. Lib App Lib Lib
  211. Open source repositories • https://github.com/SangsooNam/enumparser • https://github.com/SangsooNam/duotoneimageview Questions Sangsoo Nam

    sangsoo@spotify.com
  212. None