fir.im自動上傳apk並在釘釘通知

MaxChou7發表於2018-04-10

簡要記錄開發中遇到的事情

事件起因

最近測試提了一個問題:雖然每次開發釋出了測試版本的時候都要在釘釘群裡面通知,但是也會經常忘記了,這樣就會導致耽誤測試及修改bug的後續整個進度。

一直知道釘釘裡面有個webhook功能,同時看到fir.im裡面可以設定webhook,基於此,便可以實現上傳版本後自動通知到釘釘群裡面。

解決辦法

在釘釘裡面的機器人 可以在GitHub等平臺配置webhook後進行 push訊息提示,所以每次push都會在釘釘裡面提醒。如此,若在fir.im裡面加入hook地址應該也會在上傳apk後收到訊息提示,但是開啟fir.im後並沒有看到釘釘平臺的支援,

fir.im自動上傳apk並在釘釘通知

但是找到了一個自定義webhook設定,於是就進行了自定義的配置,但在釘釘上一直沒有收到推送訊息,無奈只好聯絡客服以幫助查詢問題,雖然客服反應較慢但最後還是給了回覆

fir.im自動上傳apk並在釘釘通知

要指向自己的伺服器,這個太麻煩了,這麼一個小功能沒有必要專門開服務(這一點還是希望fir.im可以早點對一些大平臺支援)。於是只好另想辦法,查詢fir.im的文件發現可以介面上傳安裝包,那就只好迂迴路線——介面上傳安裝包,成功後呼叫釘釘給出webhook地址傳送推送訊息。其實後面就很簡單了,主要就幾個介面呼叫而已。

最近有看python,所以打算用python來顯現一下。首先用python做了一個簡單的介面,包括有選擇安裝包以及上傳按鈕等

fir.im自動上傳apk並在釘釘通知

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()複製程式碼

雖然程式碼很短,但在整個過程中花費了較多的時間,是一個還不錯的經歷,故做記錄,同時希望對類似需求的人有所幫助。


相關文章