从零到一发布 Android 开源库
wangdi244
8年前
<p>最近在Flipboard实习期间写了一个轮播工具,技术上没什么难点,不过动画效果还是不错的,决定改改代码写个库开源出去。 <a href="/misc/goto?guid=4959676783829144864" rel="nofollow,noindex">项目地址:http://github.com/chengdazhi/DecentBanner</a> ,欢迎大家提Issue报Bug。由于国内有关发布开源库的文章与教程很少见,我就先挖个坑。</p> <p>本文力求简明,希望大家可以很快学会如何把自己写的代码开源出去,并让全世界的开发者可以通过一句compile语句来使用。毕竟重点在于库本身,而发布只是必须的过程。</p> <p>整个过程涉及以下几个工具:</p> <ul> <li> <p>Android Studio + Gradle : 用于将库独立成模块。</p> </li> <li> <p>Bintray : Bintray是用于托管库代码的地方,也是将库发布到JCenter的工具。只有库发布到JCenter,在Gradle中才可以通过一句compile命令来集成。</p> </li> <li> <p>Telecine : 用于给Android应用录屏。</p> </li> </ul> <p>过程分为以下几步:</p> <ol> <li>将代码封装在一个module中。</li> <li>通过gradle将代码上传到Bintray。</li> <li>将代码托管到GitHub,并编写README,以及后续推广与维护。</li> </ol> <p>下面以这三步为主线一步步将库开源出去。</p> <h2>封装代码</h2> <p>在这一部分中我们要把库的代码封装并生成aar文件。aar文件类似于jar,只不过由于Android还包含XML、Assets、JNI等等其他格式的文件,所以打包后的结果就是aar。</p> <p>首先在Android Studio中点击File菜单,选择New->New Module,然后在弹出视图中选择Android Library,点击Next后填写库的名称。</p> <p><img src="https://simg.open-open.com/show/a536ce0955a69b08dec823e9abbc7be6.png"></p> <p>我在这里填写decentbanner,然后在目录视图中就可以看到两个module了,一个是App的,一个是库的。(默认可运行的module名称为app,我在这里改成了demo)</p> <p><img src="https://simg.open-open.com/show/17678297efcc41907e97b6de76acbeb6.png"></p> <p>创建完新的module后就可以填充代码了,至于写什么组件倒没有关系。写好后,如果想在app module中使用新的module中的类,需要在app module下的build.gradle中添加依赖:</p> <pre> <code class="language-java">compile project(':yourmodulename') //冒号后是你的新module的名称</code></pre> <p>当你在app module下测试没有问题后,这一步就完成了。当然这里的重点在于库的代码,封装本身是没有难度的。</p> <h2>将库上传到Bintray</h2> <p><a href="/misc/goto?guid=4958860112497972326" rel="nofollow,noindex">Bintray</a> 是一个可以托管Android库的平台,平时我们在gradle中通过一句compile命令就可以引用的库,都托管在JCenter上,而JCenter则由Bintray维护。我们在这个部分中要进行的操作分两步,一是将我们的代码上传到Bintray的Maven仓库中,二是将Maven仓库发布到JCenter。在这一部分中Gradle是核心,所以如果你哪个地方出了问题,我在这个部分末尾给出了几个gradle文件的GitHub地址可以供大家参考。</p> <p>当你完成注册并登录到Bintray后,你会发现有九个仓库可供你使用,点View All后你会看到Maven选项。这里不需要进行任何操作,只需要知道我们要使用Maven进行上传即可。我们这里真正需要的是API Key,后面当我们在上传库时需要提供username和API key,具体在哪里后面再说。大家不妨先在网站里到处逛逛。</p> <p><img src="https://simg.open-open.com/show/2d1567bf5826f90ac98b6dbf2845de98.png"></p> <h3>Maven</h3> <p>首先我们因为要使用到Bintray和Maven的服务,我们需要在项目根目录下的build.gradle中添加两行classpath。具体的文档可以参考 <a href="/misc/goto?guid=4959676783944455276" rel="nofollow,noindex">Bintray plugin</a> 和 <a href="/misc/goto?guid=4959676784020967983" rel="nofollow,noindex">Maven plugin</a> 。</p> <pre> <code class="language-java">classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2' classpath "com.github.dcendents:android-maven-gradle-plugin:1.3"</code></pre> <p>这里依赖的插件版本低于GitHub文档中的最新版本,因为我依赖最新版时发现Android Studio会报错,信息是库不兼容,如果你没有这个问题,当然还是最新版最好。在添加完classpath后,要在你的库module中依赖新的插件,只需将下面两行添加到库module目录中的build.gradle文件即可。</p> <pre> <code class="language-java">apply plugin: 'com.jfrog.bintray' apply plugin: 'com.github.dcendents.android-maven'</code></pre> <p>Bintray在上传库时需要一个POM文件,而这个文件可以让Maven插件自动生成,但你还是需要给出groupId和version的值,只需要将下面这两行代码添加到库module的build.gradle中即可。</p> <pre> <code class="language-java">group = '你的库的包名' // 这里需要和真实包名对应,不能随便填写 version = '1.0.1' // 指定版本号</code></pre> <p>为了与Maven标准对应,你需要在库module的build.gradle中添加几个task,分别生成Jar,Javadoc和JavadocsJar,只需要将下面三个task代码添加到gradle文件即可。</p> <pre> <code class="language-java">task generateSourcesJar(type: Jar) { from android.sourceSets.main.java.srcDirs //通过from函数指定代码源,这里是默认代码源 classifier 'sources' } task generateJavadocs(type: Javadoc) { source = android.sourceSets.main.java.srcDirs //source指定了代码源 classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } //这里dependsOn意为仅当generateJavadocs完成后才开始本task task generateJavadocsJar(type: Jar, dependsOn: generateJavadocs) { from generateJavadocs.destinationDir classifier 'javadoc' }</code></pre> <p>为了将你生成的源代码和Javadoc Jar文件添加到Maven中,你需要将task添加到一个archive中,只需要向库module下的build.gradle中添加如下代码:</p> <pre> <code class="language-java">artifacts { archives generateJavaDocsJar archives generateSourcesJar }</code></pre> <h3>Bintray</h3> <p>到这里我们已经配置好了Maven插件,现在需要配置Bintray插件。在编写代码前,我们需要提供username和API key,username就是你注册时填写的,如果你直接用GitHub登录,那么username就是GitHub的username。要找到API key,首先进入个人主页,即点击Bintray主页右上角的头像并点击Your Profile,然后点击头像右侧大大的Edit按钮,而后在左侧找到API Key选项即可。</p> <p><img src="https://simg.open-open.com/show/ca0285964bce9cbedfbd6ab8b3d860d5.png"></p> <p>我们在这里先将这两个值写在local.properties下,因为这种数据是不应该传到GitHub的。</p> <pre> <code class="language-java">bintray.user=your_username bintray.apikey=your_apikey</code></pre> <p>而后我们继续在库module下的build.gradle中添加如下代码块,这里我直接贴了我的代码,方便大家参阅,请大家对具体的值进行修改。在这里有一个license属性,马上就要说到如何选择一个license。license只是声明别人在使用你的代码时的权限,不需要申请,选择之后直接在项目中添加一个相应的LICENSE文件即可。除此之外,</p> <pre> <code class="language-java">//需要在local.properties文件中取值 Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) bintray { user = properties.getProperty("bintray.user") key = properties.getProperty("bintray.apikey") pkg { repo = 'maven' name = 'it.chengdazhi.decentbanner' version { name = '1.0.5-tuts' desc = "decent banner" released = new Date() vcsTag = '1.0.5' } } configurations = ['archives'] }</code></pre> <p>在选择License时,可以参考这张图,来自阮一峰老师的 <a href="/misc/goto?guid=4959676784103066004" rel="nofollow,noindex">博文</a> 。刚才说过,选择License只是选择一种权利,选好之后可以直接添加就好。 <strong>GitHub在创建Repo时可以快速添加License文件。</strong></p> <p><img src="https://simg.open-open.com/show/656b835531df31df56db58b42485c9de.png"></p> <p>以上除了两行classpath写在根目录build.gradle,以及username和apikey写在local.properties下,其余修改的全部是库module下的build.gradle文件,完整文件可以参考 <a href="/misc/goto?guid=4959676784185725819" rel="nofollow,noindex">我的源码</a> 。到这里我们完成了所有gradle的编写,现在我们需要进入Gradle Window视图,默认在Android Studio的右侧,处在最小化状态,找不到可以从菜单点击View->Tool Windows->Gradle调出。点击图标栏的Gradle图标。</p> <p><img src="https://simg.open-open.com/show/9abbe418f4adf70eb1e212cdf8112190.png"></p> <p>输入install,点击OK。注意这里的Gradle project是你的库module。这时会执行Maven相关的task。</p> <p><img src="https://simg.open-open.com/show/70b609488921915f0e3ca550102c76cd.png"></p> <p>而后你的库module的build目录下会出现POM文件,AAR文件,源代码Jar文件和Javadocs Jar文件。</p> <p><img src="https://simg.open-open.com/show/0542234946e62f30004821b537cd15e1.png"></p> <p>成功后再次点击Gradle图标,输入bintrayUpload并点击OK。执行成功后你的库就成功上传到Bintray了。注意以后每次更新库时需要更新版本号,不然会冲突,同时每次都需要顺序执行install和bintrayUpload。上传成功后你可以在Bintray主页左下角的My Recent Packages栏目中看到新的package。</p> <p><img src="https://simg.open-open.com/show/1743f0edddab101d9dcb4329c9c2b4ad.png"></p> <p>点进去后会有这样一个提示,让你在七天之内公开,点击Publish。</p> <p><img src="https://simg.open-open.com/show/90500ab431346dcd3fd0ecf192e15023.png"></p> <h3>JCenter</h3> <p>然后为了让所有开发者都可以使用,你需要将类库添加到JCenter。操作很简单,只需要点击如下所示的按钮,而后你需要填写有关类库的信息。</p> <p><img src="https://simg.open-open.com/show/328bb0016b05271ee5654f35331e4e3f.png"></p> <p>我提交之后过几个小时就有邮件通知添加成功,大家耐心等待。添加成功后会变成如下景象。</p> <p><img src="https://simg.open-open.com/show/606ce80533b5df1c366d759cfa1b867c.png"></p> <p>在每次发新版时,点击Publish后不会立即生效,也就是说如果在Gradle中想要立即引用新版,会无法解析,因为有几分钟的延迟,等到左下角的Maven build Settings中的依赖代码改变,或是右上侧Version栏目下新版信息有了tweeter标识后就可以正常引用了。</p> <p><img src="https://simg.open-open.com/show/a7af45149d4ad8a4ed6abafe073d5b88.png"></p> <p><img src="https://simg.open-open.com/show/d6a622c995fc1d9ddcd149ccb5a8f72f.png"></p> <h2>托管到GitHub,写readme,推广与维护</h2> <p>恭喜你,你已经完成了所有有坑的环节,现在离完成只剩一个GitHub了!GitHub对于你的开源库而言有如下几个作用,一是可以维护一份文档,也就是README,告知大家相关信息;二是可以将代码以很方便的形式让大家参考并做二次开发;第三点在于GitHub是世界上最大的同性交友平台,是所有开源库的集散地;第四点在于大家可以很方便的提交Issue给你报Bug。</p> <h3>README</h3> <p>有很多文章讲了如何将项目托管到GitHub,这里不再重述。首先我们说说README这个文件。在GitHub的每个项目中,根目录中的README.md会被用于展示,大家可以在这个文档中展示库的相关信息,至少要包含依赖语句。除此以外,我建议大家在README中添加以下几项信息:</p> <ul> <li> <p>效果展示:如果你做的是View,那么给出一个截图或是Gif,如果是其他组件,最好也给出可视化很强的图片,因为图片对人的冲击力远大于文字。如果你要做动图,并进行图片录制的话,首先推荐一个录屏工具 <a href="/misc/goto?guid=4958861875055353007" rel="nofollow,noindex">Telecine</a> ,Jake Wharton出品,无需root,方便传输,这是我对比多个市场上下载量最大的录屏工具后作出的推荐。然后,在你将视频转成gif后,可以使用Photoshop对Gif进行裁剪与剪辑,只需打开时间轴窗口即可,很方便。 建议你将gif图片放在项目目录中,而不是在README中以外链形式添加,不然可能显示异常。</p> </li> <li> <p>样例下载:开发者如果被你的展示图所吸引,会希望能下载一个样例。建议大家能同时给出apk的下载链接和二维码。由于国内很多人通过微信扫二维码,而微信浏览器又不支持下载,大家需要给服务器上的apk文件设置请求头,将Content-Type设置为application/octet-stream,强制微信跳转到外部浏览器。</p> </li> <li> <p>功能与使用范例:给出支持的功能与相对应的最基本的使用方式,最好做出相关说明,比如参数等等。</p> </li> <li> <p>License:把刚才选择的License添加到README中。</p> </li> </ul> <p>大家不妨多参考Star数很高的开源项目的README。</p> <h3> </h3> <p>来自:http://blog.chengdazhi.com/index.php/217</p> <p> </p>