本系列代码地址 githubjava
相关资料 gradle in action中英文对照版android
回到目录git
咱们在上一边已经将“publishReleaseRelease”和“assembleRelease”这两个任务关联起来了。并已经肯定了“publishReleaseRelease”执行前会先执行“assembleRelease”,接下来就是把“assembleRelease”执行完后生成的apk来上传到蒲公英了。 咱们先来介绍下蒲公英。github
蒲公英官网api
蒲公英提供专业的手机应用内测服务,您只需将须要内测的应用上传至蒲公英,生成二维码,内测用户经过在手机上扫描二维码,便可将内测应用安装至手机等设备中进行测试。app
当咱们把内测的apk上传到蒲公英之后,会生成一个安装页面,以下:dom
这样,测试人员就能够在这个下载页面下载对应的版本进行测试。并且这个页面还会保存版本的历史记录,方便咱们进行版本对比。工具
咱们能够在蒲公英的后台进行手动上传,但咱们要实现的是让上传过程自动化。post
蒲公英提供了一个api接口来提供apk文件上传,网址。基本上是很简单的,就不详细说了,看文档就能够了。测试
接下来实现apk文件上传功能。
咱们先写一个工具类,来实现http的文件上传功能,代码以下:
class MultipartUtility {
private final String boundary = UUID.randomUUID().toString()
private static final String LINE_FEED = "\r\n"
private HttpURLConnection httpConn
private String charset
private OutputStream outputStream
private PrintWriter writer
/** * This constructor initializes a new HTTP POST request with content type * is set to multipart/form-data * * @param requestURL * @param charset * @throws IOException */
MultipartUtility(String requestURL, String charset)
throws IOException {
this.charset = charset
URL url = new URL(requestURL)
// Log.e("URL", "URL : " + requestURL.toString());
println "URL : " + requestURL.toString()
httpConn = (HttpURLConnection) url.openConnection()
// httpConn = url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(8888)))
httpConn.setRequestMethod("POST")
httpConn.setUseCaches(false)
httpConn.setDoOutput(true) // indicates POST method
httpConn.setDoInput(true)
httpConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary)
// httpConn.setRequestProperty("User-Agent", "CodeJava Agent")
// httpConn.setRequestProperty("Test", "Bonjour")
outputStream = httpConn.getOutputStream()
writer = new PrintWriter(new OutputStreamWriter(outputStream, charset), true)
}
/** * Adds a form field to the request * * @param name field name * @param value field value */
void addFormField(String name, String value) {
writer.append("--" + boundary).append(LINE_FEED)
writer.append("Content-Disposition: form-data; name=\"" + name + "\"")
.append(LINE_FEED)
writer.append("Content-Type: text/plain; charset=" + charset).append(
LINE_FEED)
writer.append(LINE_FEED)
writer.append(value).append(LINE_FEED)
writer.flush()
}
/** * Adds a upload file section to the request * * @param fieldName name attribute in <input type="file" name="..." /> * @param uploadFile a File to be uploaded * @throws IOException */
void addFilePart(String fieldName, File uploadFile) throws IOException {
String fileName = uploadFile.getName()
writer.append("--" + boundary).append(LINE_FEED)
writer.append(
"Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + fileName + "\"")
.append(LINE_FEED)
writer.append("Content-Type: " + "application/vnd.android.package-archive")
.append(LINE_FEED)
writer.append("Content-Transfer-Encoding: binary")
.append(LINE_FEED)
writer.append(LINE_FEED)
writer.flush()
FileInputStream inputStream = new FileInputStream(uploadFile)
byte[] buffer = new byte[1024 * 6]
int bytesRead = -1
int countBytes = 0
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead)
outputStream.flush()
countBytes += bytesRead
}
println "countBytes:${countBytes}"
inputStream.close()
// writer.append(LINE_FEED)
writer.flush()
}
/** * Adds a header field to the request. * * @param name - name of the header field * @param value - value of the header field */
void addHeaderField(String name, String value) {
writer.append(name + ": " + value).append(LINE_FEED)
writer.flush()
}
/** * Completes the request and receives response from the server. * * @return a list of Strings as response in case the server returned * status OK, otherwise an exception is thrown. * @throws IOException */
String finish() throws IOException {
StringBuffer response = new StringBuffer()
writer.append(LINE_FEED).flush()
writer.append("--" + boundary + "--").append(LINE_FEED)
writer.close()
// checks server's status code first
int status = httpConn.getResponseCode()
if (status == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(
httpConn.getInputStream()))
String line = null while ((line = reader.readLine()) != null) {
response.append(line)
}
reader.close()
httpConn.disconnect()
} else {
throw new IOException("Server returned non-OK status: " + status)
}
return response.toString()
}
}
复制代码
接下来咱们建立一个任务“uploadPgyerByApi”,代码以下:
task uploadPgyerByApi() {
doLast {
//apk打包完成后存在的位置
def file_path = "./build/outputs/apk/release/app-release-unsigned.apk"
//apk上传api url
def api_url = "http://www.pgyer.com/apiv2/app/upload"
//用户api_key 可从蒲公英后台获取
def api_key = "1540c89d7f12ade530a14ac4ad******"
//用户user_key 可从蒲公英后台获取
def user_key = "15391e4e9f1d62962b97ff630d******"
MultipartUtility utility = new MultipartUtility(api_url, "UTF-8")
utility.addFormField("_api_key", api_key)
utility.addFormField("userKey", user_key)
utility.addFormField("buildInstallType", "2")
utility.addFormField("buildPassword", "123456")
utility.addFormField("buildUpdateDescription", "serverName")
utility.addFilePart("file", file(file_path))
def result = utility.finish()
println result
}
}
复制代码
“uploadPgyerByApi”这个task在doLast这个action中实现了apk文件的上传。“file_path”这参数指定了“assembleRelease”这个任务执行完成后生成的apk所在的位置,即咱们要上传的apk的文件路径。
这样咱们apk文件上传的task便完成了。接下来就须要把“uploadPgyerByApi”和“publishReleaseRelease”这两个任务串在一块儿。咱们在“publishReleaseRelease”这个task的最后样加入以下代码:
finalizedBy(uploadPgyerByApi)
复制代码
即为:
task publishReleaseRelease(dependsOn: "assembleRelease") {
group "publish"
doFirst {
println "publishReleaseRelease doFirst called......"
}
doLast {
println "publishReleaseRelease doLast called......"
}
finalizedBy(uploadPgyerByApi)
}
复制代码
这样咱们就实现了这样一个流程: 1.打包应用 2.上传apk文件到蒲公英
咱们执行“publishReleaseRelease”这个task,获得以下结果:
咱们看到,“assembleRelease”,“publishReleaseRelease”,“uploadPgyerByApi”这三个任务依次执行了,咱们到蒲公英后台看一下,发现apk已经上传完成:
fir上传的实现和蒲公英的基本一致,感兴趣的同窗能够本身实现如下,就当练习了。