本系列代碼地址 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上傳的實現和蒲公英的基本一致,感興趣的同窗能夠本身實現如下,就當練習了。