簡要記錄開發中遇到的事情
事件起因
最近測試提了一個問題:雖然每次開發釋出了測試版本的時候都要在釘釘群裡面通知,但是也會經常忘記了,這樣就會導致耽誤測試及修改bug的後續整個進度。
一直知道釘釘裡面有個webhook功能,同時看到fir.im裡面可以設定webhook,基於此,便可以實現上傳版本後自動通知到釘釘群裡面。
解決辦法
在釘釘裡面的機器人 可以在GitHub等平臺配置webhook後進行 push訊息提示,所以每次push都會在釘釘裡面提醒。如此,若在fir.im裡面加入hook地址應該也會在上傳apk後收到訊息提示,但是開啟fir.im後並沒有看到釘釘平臺的支援,
但是找到了一個自定義webhook設定,於是就進行了自定義的配置,但在釘釘上一直沒有收到推送訊息,無奈只好聯絡客服以幫助查詢問題,雖然客服反應較慢但最後還是給了回覆
要指向自己的伺服器,這個太麻煩了,這麼一個小功能沒有必要專門開服務(這一點還是希望fir.im可以早點對一些大平臺支援)。於是只好另想辦法,查詢fir.im的文件發現可以介面上傳安裝包,那就只好迂迴路線——介面上傳安裝包,成功後呼叫釘釘給出webhook地址傳送推送訊息。其實後面就很簡單了,主要就幾個介面呼叫而已。
最近有看python,所以打算用python來顯現一下。首先用python做了一個簡單的介面,包括有選擇安裝包以及上傳按鈕等
python很不熟練,可能很多東西都使用不當,比如沒有非同步請求介面等,花了較久的時間寫程式碼,最終達到了自己的目的。在傳送到釘釘的提醒訊息裡面有下載地址,我這裡是在程式碼裡面配置死了的。推送釘釘的訊息樣式可以參考open-doc.dingtalk.com/docs/doc.ht…定製。以下是程式碼
# -*- coding: utf-8 -*-
from tkinter import *
from tkinter import messagebox
import tkinter.filedialog
import requests
import os
import re
import subprocess
import zipfile
import json
root = Tk()
root.title('APK上傳fir.im')
root.geometry('600x400')
path = StringVar()
pathShow = StringVar() # 顯示檔名
#預設的一個apitoken
apiTokenDefult = "你的預設apitoken"
packagename = ""
versionCode = 0
versionName = ""
name = ""
saveIconName = ""
mfmUrl = "XXX"
mfmPwd = "XXX"
fgcUrl = "XXX"
fgcPwd = "XXX"
fgjUrl = "XXX"
fgjPwd = "XXX"
#這裡是釘釘訊息需要@的人的手機號
atList = ["12345","12345"]
#這裡是webhook地址
notifyUrl = "https://oapi.dingtalk.com/robot/send?access_token=XXX"
def appInfo():
#根據自己的aapt地址修改
output = subprocess.Popen('D:/android_sdk/build-tools/21.0.0/aapt dump badging ' + path.get(),
shell=False,stdout=subprocess.PIPE).stdout.readlines()
for line in output:
if "package: name" in line.decode():
match = re.compile("package: name='(\S+)' versionCode='(\d+)' versionName='(\S+)'").match(line.decode())
global packagename
packagename = match.group(1)
global versionCode
versionCode = match.group(2)
global versionName
versionName = match.group(3)
if 'application: label' in line.decode():
matchName = re.compile("application: label='(\S+)'").match(line.decode())
global name
name = matchName.group(1)
if 'application-icon-320:' in line.decode():
icon = re.compile("application-icon-320:'(\S+)'").match(line.decode())
iconPath = icon.group(1)
#儲存到本地
zz = zipfile.ZipFile( path.get() )
iconData = zz.read(iconPath)
global saveIconName
#臨時儲存icon的位置
saveIconName = "D:/python3.6/icon.png";
with open(saveIconName,'w+b') as saveIconFile:
saveIconFile.write(iconData)
def selectPath():
path_ = tkinter.filedialog.askopenfilename(filetypes=[("apk檔案", ".apk")])
path.set(path_)
temp = path.get().split('/')
pathShow.set(temp[len(temp)-1])
appInfo()
def doSubmit():
if not packagename or not versionName or not name or versionCode==0:
messagebox.showinfo('提示','獲取apk資訊失敗')
return
res = requests.post("http://api.fir.im/apps",data={"type":"android","bundle_id":packagename,
"api_token":apiToken.get() or apiTokenDefult})
if res.status_code != 201:
messagebox.showinfo('提示','請求返回錯誤')
return
data = res.json()
icon = data['cert']['icon']
apk = data['cert']['binary']
#上傳icon
uploadIcon = requests.post(icon['upload_url'],data={"key":icon['key'],'token':icon['token']},
files={'file':('icon.png',open(saveIconName,'rb'))})
if uploadIcon.status_code!=200:
messagebox.showinfo('提示',"上傳ICON成功")
return
#上傳檔案
upload = requests.post(apk['upload_url'],data={"key":apk['key'],'token':apk['token'],
'x:name':name,'x:version':versionName,'x:build':versionCode,
'x:changelog':des.get()},
files={'file':(pathShow.get(),open(path.get(),'rb'))})
if upload.status_code==200 and upload.json()["is_completed"]==True:
messagebox.showinfo('提示',"上傳成功")
#通知推送訊息
downUrl = ""
downPwd = ""
if "maifangma" in packagename:
downUrl = mfmUrl
downPwd = mfmPwd
elif "fangguancha" in packagename:
downUrl = fgcUrl
downPwd = fgcPwd
elif "fangguanjia" in packagename:
downUrl = fgjUrl
downPwd = fgjPwd
else:
messagebox.showinfo('提示',"下載地址無效")
listat = ""
for at in atList:
listat+="@"+at
data = {"msgtype": "markdown",
"markdown":{"title":name+"新版本",
"text":"### "+name+"Android新版本\n"+"> 版本:"+versionName+"\n\n> 更新描述:"+
des.get()+"\n\n> [點選下載("+ ("無效連結" if not downPwd else ("密碼:"+downPwd)) +")]("+downUrl+")\n\n > "+listat},
"at":{"atMobiles":atList}}
notify = requests.post(notifyUrl,data=json.dumps(data),
headers={"Content-Type":"application/json;charset=utf-8"})
else:
messagebox.showinfo('提示',"上傳失敗:"+upload.status_code)
Label(root,text='api_token:',width=20).grid(row=0,column=0)
apiToken = Entry(root)
apiToken.grid(row=0,column=1)
Label(root,text='檔案路徑:').grid(row=1,column=0)
Button(root, text = "選擇檔案", command = selectPath).grid(row = 1, column = 1)
Label(root, textvariable = pathShow,bg='white').grid(row = 2, column = 1,columnspan = 2)
Label(root,text='更新描述:').grid(row=3,column=0)
des = Entry(root)
des.grid(row=3,column=1,rowspan=3,sticky=E)
Button(root,text="上傳",command=doSubmit).grid(row = 6,column = 1)
root.mainloop()複製程式碼
雖然程式碼很短,但在整個過程中花費了較多的時間,是一個還不錯的經歷,故做記錄,同時希望對類似需求的人有所幫助。