python一鍵實(shí)現(xiàn)apk編譯打包、上傳蒲公英哀墓、企業(yè)微信機(jī)器人提醒

編譯腳本組成

1681351227078.png

1趁餐、buildApk.py:位于根目錄,調(diào)用不同平臺(tái)shell的gradlew clean 和 根據(jù)用戶選擇gradlew assembleRelease或者 gradlew assembleDebug 篮绰,調(diào)用UploadUtil.uploadPuGongYing(vSysInfo=vSysInfo)上傳到蒲公英平臺(tái)
2后雷、upload_pgyer.py:蒲公英官方api 2.0上傳apk,獲取上傳后的apk信息
3吠各、upload.py: 調(diào)用蒲公英官方上傳api, 將獲取到apk信息發(fā)送到企業(yè)微信群機(jī)器人提醒
4臀突、buildUpdateMsg.txt:更新日志,此內(nèi)容會(huì)更新到蒲公英更新描述和企業(yè)微信群內(nèi)

編譯環(huán)境

1贾漏、安裝python 3版本
2候学、使用pip install requests庫(kù)
3、執(zhí)行python buildApk.py

buildApk.py

# -*- coding: utf-8 -*-
# -*- author: zhoulikai-*-
import subprocess
import os
import time
import platform
from buildScript import upload as UploadUtil


import sys
import shutil
from pathlib import Path


def main():
    tip = """
    請(qǐng)輸入編譯0:debug 1:release
    0纵散、debug
    1梳码、release
    """
    print(tip)
    vSys = input("")
    vSysInfo = "Debug"
    if vSys == "1":
        vSysInfo = "Release"
    else:
        vSysInfo = "Debug"
    print("編譯版本:" + vSysInfo)
    print("*********************************編譯開(kāi)始**********************************")
    #刪除以前的編譯文件
    # apkFiles = os.path.join(os.getcwd(), "releaseApks")
    # if (os.path.exists(apkFiles)):
    #     print("緩存目錄存在")
    #     for root, dirs, files in os.walk(apkFiles, topdown=False):
    #         for name in files:
    #             print(name)
    #             os.remove(os.path.join(root, name))
    #         for name in dirs:
    #             print(name)
    #             os.rmdir(os.path.join(root, name))
    #     time.sleep(3)
    #     os.rmdir(apkFiles)

    print("開(kāi)始執(zhí)行 gradlew clean")
    systemInfo = platform.system().lower()
    print("編譯系統(tǒng):%s" % systemInfo)
    commond = os.path.join(os.getcwd(), "gradlew.bat" if systemInfo == "windows" else "gradlew")
    # cleanResult = os.system(commond)
    # print(cleanResult)
    # cleanResult = subprocess.call([commond, "clean"],shell=True)
    cleanResult = os.system(commond + " clean")
    # cleanResult = 0
    if (cleanResult == 0):
        print("執(zhí)行 gradlew clean結(jié)束")
        print("開(kāi)始執(zhí)行 gradlew assemble")
        # assembleResult = subprocess.call([commond, "assemble" + vSysInfo],shell=True)
        assembleResult = os.system(commond + " assemble" + vSysInfo)
        # assembleResult = 0
        if (assembleResult == 0):
            print("執(zhí)行g(shù)radlew assemble成功")
            print("*********************************編譯結(jié)束**********************************")
            UploadUtil.uploadPuGongYing(vSysInfo=vSysInfo)
        else:
            print("執(zhí)行g(shù)radlew assemble失敗")
    else:
        print("執(zhí)行g(shù)radlew clean 失敗")

if __name__ == "__main__":
    main()

upload_pgyer.py

# -*- coding: utf-8 -*-
# -*- author: LinXunFeng -*-

import time
import requests

# 官方文檔
# https://www.pgyer.com/doc/view/api#fastUploadApp

def _getCOSToken(
    api_key, 
    install_type, 
    password='', 
    update_description='', 
    callback=None
):
  """
  獲取上傳的 token
  """
  headers = {'enctype': 'multipart/form-data'}
  payload = {
    '_api_key': api_key, # API Key
    'buildType': 'android', # 需要上傳的應(yīng)用類型隐圾,ios 或 android
    'buildInstallType': install_type, # (選填)應(yīng)用安裝方式,值為(1,2,3边翁,默認(rèn)為1 公開(kāi)安裝)。1:公開(kāi)安裝硕盹,2:密碼安裝符匾,3:邀請(qǐng)安裝
    'buildPassword': password, # (選填) 設(shè)置App安裝密碼,密碼為空時(shí)默認(rèn)公開(kāi)安裝
    'buildUpdateDescription': update_description, # (選填) 版本更新描述瘩例,請(qǐng)傳空字符串啊胶,或不傳。
  }
  try:
    r = requests.post('https://www.pgyer.com/apiv2/app/getCOSToken', data=payload, headers=headers)
    if r.status_code == requests.codes.ok:
      result = r.json()
      # print(result)
      if callback is not None:
        callback(True, result)
    else:
      if callback is not None:
          callback(False, None)
  except Exception as e:
    print('服務(wù)器暫時(shí)無(wú)法為您服務(wù)', e)


def upload_to_pgyer(path, api_key, install_type=2, password='', update_description='', callback=None):
    """
    上傳到蒲公英
    :param path: 文件路徑
    :param api_key: API Key
    :param install_type: 應(yīng)用安裝方式垛贤,值為(1,2,3)焰坪。1:公開(kāi),2:密碼安裝聘惦,3:邀請(qǐng)安裝某饰。默認(rèn)為1公開(kāi)
    :param password: App安裝密碼
    :param update_description:
    :return: 版本更新描述
    """

    def getCOSToken_callback(isSuccess, json):
      if isSuccess:
        _upload_url = json['data']['endpoint']
        
        files = {'file': open(path, 'rb')}
        headers = {'enctype': 'multipart/form-data'}
        payload = json['data']['params']
        print("上傳中...")
        
        try:
          r = requests.post(_upload_url, data=payload, files=files, headers=headers)
          if r.status_code == 204:
            # result = r.json()
            # print(result)
            print("上傳成功,正在獲取包處理信息善绎,請(qǐng)稍等...")
            _getBuildInfo(api_key=api_key, json=json, callback=callback)
          else:
            print('HTTPError,Code:'+ str(r.status_code))
            if callback is not None:
              callback(False, None)
        except Exception as e:
          print('服務(wù)器暫時(shí)無(wú)法為您服務(wù)', e)
      else:
          pass

    _getCOSToken(
      api_key=api_key, 
      install_type=install_type, 
      password=password, 
      update_description=update_description, 
      callback=getCOSToken_callback,
    )

def _getBuildInfo(api_key, json, callback=None):
    """
    檢測(cè)應(yīng)用是否發(fā)布完成黔漂,并獲取發(fā)布應(yīng)用的信息
    """
    time.sleep(3) # 先等個(gè)幾秒,上傳完直接獲取肯定app是還在處理中~
    response = requests.get('https://www.pgyer.com/apiv2/app/buildInfo', params={
      '_api_key': api_key,
      'buildKey': json['data']['params']['key'],
    })
    if response.status_code == requests.codes.ok:
      result = response.json()
      code = result['code']
      if code == 1247 or code == 1246: # 1246   應(yīng)用正在解析禀酱、1247 應(yīng)用正在發(fā)布中
        print("------_getBuildInfo-------")
        _getBuildInfo(api_key=api_key, json=json, callback=callback)
      else:
        if callback is not None:
          callback(True, result)
    else:
      if callback is not None:
        callback(False, None)


upload.py

# -*- coding: utf-8 -*-
# -*- author: zhoulikai -*-

from buildScript import upload_pgyer as PgyerUtil
import os
import requests
import json
import platform

#配置信息
os.environ['NO_PROXY']="www.pgyer.com,qyapi.weixin.qq.com"
pgyer_api_key = 'API KEY' # API KEY
pgyer_password = '1234' # 安裝密碼
update_description = ""
webhook_url="企業(yè)微信機(jī)器人webhook地址"
buildTime = ""
userBuild = ""
#讀取更新內(nèi)容
def readUpdateMsg():
  f = open('buildUpdateMsg.txt', 'r', encoding='utf-8')
  try:
    lines = f.readlines()
    # print(lines)
    return lines
  finally:
    f.close()
  pass

#發(fā)送企業(yè)微信機(jī)器人消息
def send_wechat_msg(content, webhook_url= "你的機(jī)器人webhook地址"):
  headers = {"content-type": "application/json"}
  data = {"msgtype": "markdown", "markdown": {"content": content, "mentioned_list":["@all"]} }
  r = requests.post(headers=headers, url=webhook_url, data=json.dumps(data, ensure_ascii=False).encode('utf-8'), verify=False)
  return r.status_code, r.text

#上傳蒲公英平臺(tái)
def uploadPuGongYing(vSysInfo="Release"):
  def upload_complete_callback(isSuccess, result):
    if isSuccess:
      print('上傳完成')
      print(result)
      _data = result['data']
      _url = _data['buildShortcutUrl'].strip() # 去除首尾空格
      _appVer = _data['buildVersion']
      _buildVer = _data['buildBuildVersion']
      # print('鏈接: https://www.pgyer.com/%s'%_url)
      # print('版本: %s (build %s)'%(_appVer, _buildVer))
      print("*********************************上傳apk結(jié)束**********************************")
      _buildName = _data['buildName']
      _buildVersion = _data['buildVersion']
      _buildVersionNo = _data['buildVersionNo']
      _buildFileSize = _data['buildFileSize']
      _buildUpdated = _data['buildUpdated']
      _buildKey=_data['buildKey'].strip()
      _buildUrl = 'https://www.pgyer.com/{buildKey}'.format(buildKey=_buildKey)
      _updateDess = update_description.replace('\n', ";")
      _buildQRCodeURL = _data['buildQRCodeURL']
      _buildSystem = platform.system().lower()
      content = """
      應(yīng)用更新提醒
      您的應(yīng)用上傳了新版本
      應(yīng)用名稱:{buildName}
      應(yīng)用類型:{buildPlatform}
      版本信息:{buildVersion}(Build {buildVersionNo})
      應(yīng)用大芯媸亍:{buildFileSize}M
      安裝密碼:{pgyerPassword}
      編譯系統(tǒng):{buildSystem}
      編譯用戶: {userBuild}
      編譯類型:{vSysInfo}
      編譯時(shí)間: {buildTime}
      更新時(shí)間:{buildUpdated}
      更新內(nèi)容:{update_description}
      點(diǎn)擊查看應(yīng)用:[{buildUrl}]({buildUrl})
      下載二維碼:![下載二維碼]({buildQRCodeURL})
      """.format(buildName=_buildName,
                 buildPlatform="Android",
                 buildVersion=_buildVersion,
                 buildVersionNo=_buildVer,
                 buildTime=buildTime,
                 buildSystem=_buildSystem,
                 buildFileSize=round(int(_buildFileSize) / 1024 / 1024, 2),
                 pgyerPassword=pgyer_password,
                 buildUpdated=_buildUpdated,
                 update_description=_updateDess,
                 buildUrl=_buildUrl,
                 userBuild=userBuild,
                 vSysInfo=vSysInfo,
                 buildQRCodeURL=_buildQRCodeURL)
      print(content)
      print("*********************************企業(yè)微信提醒開(kāi)始**********************************")
      status_code, text = send_wechat_msg(content=content, webhook_url=webhook_url)
      print("微信提醒", status_code, text)
      print("*********************************企業(yè)微信提醒結(jié)束**********************************")
    else:
      print('上傳失敗')


  rootDir = os.path.abspath(".")
  print("編譯的根目錄:%s" %rootDir)
  #buildApkPath = "releaseApks/" + vSysInfo.lower()
  buildApkPath = "app/build/outputs/apk/" + vSysInfo.lower()
  apkDir = os.path.join(rootDir, buildApkPath)
  print("編譯的apk路徑:%s" % apkDir)
  fileList = os.listdir(apkDir)
  fileList = [os.path.join(apkDir, f) for f in fileList if f.endswith(".apk")]
  print(fileList)
  size = len(fileList)
  if size != 1:
    print("編譯文件錯(cuò)誤")
  else:
    f = fileList[0]
    print("要上傳的文件 %s" %f)
    app_path = f
    fileName = os.path.basename(app_path)
    print("要上傳的文件路徑:%s" %fileName)
    files = fileName.replace(".apk", "").split('_')
    buildTime = files[3][0:4] + "-" + files[3][4:6] + "-" + files[3][6:] + " " + files[4][0:2] + ":" + files[4][2:4] + ":" + files[4][4:]
    print("編譯時(shí)間:%s" %buildTime)
    userBuild = os.getlogin()
    print("編譯用戶名:%s" %userBuild)
    updateMsgs = readUpdateMsg()
    update_description = ""
    print("*********************************更新內(nèi)容開(kāi)始**********************************")
    for msg in updateMsgs:
      update_description += msg
      print(msg)
    print("*********************************更新內(nèi)容結(jié)束**********************************")
    print("*********************************上傳apk開(kāi)始**********************************")
    PgyerUtil.upload_to_pgyer(
      path = app_path,
      api_key = pgyer_api_key,
      password=pgyer_password,
      update_description=update_description,
      callback=upload_complete_callback
    )

#編譯腳本執(zhí)行入口
def main():
  uploadPuGongYing()
if __name__ == "__main__":
  main()

注意 apk文件名稱定義,目的腳本獲取到編譯時(shí)間及編譯類型

android.applicationVariants.all { variant ->
            variant.outputs.all {output->
//                output.getPackageApplication().outputDirectory = new File(project.rootDir.absolutePath + "/releaseApks/${buildType.name}")
                def buildTime = new Date().format("YYYYMMdd_HHmmss", TimeZone.getTimeZone("GMT+08:00"))
                outputFileName = "App_${defaultConfig.versionName}_${buildType.name}_${buildTime}.apk"
            }
        }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末剂跟,一起剝皮案震驚了整個(gè)濱河市减途,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌曹洽,老刑警劉巖鳍置,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異送淆,居然都是意外死亡墓捻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)坊夫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)砖第,“玉大人,你說(shuō)我怎么就攤上這事环凿∥嗉妫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵智听,是天一觀的道長(zhǎng)羽杰。 經(jīng)常有香客問(wèn)我渡紫,道長(zhǎng),這世上最難降的妖魔是什么考赛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任惕澎,我火速辦了婚禮,結(jié)果婚禮上颜骤,老公的妹妹穿的比我還像新娘唧喉。我一直安慰自己,他們只是感情好忍抽,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布八孝。 她就那樣靜靜地躺著,像睡著了一般鸠项。 火紅的嫁衣襯著肌膚如雪干跛。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天祟绊,我揣著相機(jī)與錄音楼入,去河邊找鬼。 笑死牧抽,一個(gè)胖子當(dāng)著我的面吹牛浅辙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阎姥,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼记舆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了呼巴?” 一聲冷哼從身側(cè)響起泽腮,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衣赶,沒(méi)想到半個(gè)月后诊赊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡府瞄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年碧磅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遵馆。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鲸郊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出货邓,到底是詐尸還是另有隱情秆撮,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布换况,位于F島的核電站职辨,受9級(jí)特大地震影響盗蟆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜舒裤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一喳资、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腾供,春花似錦仆邓、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)绒北。三九已至黎侈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間闷游,已是汗流浹背峻汉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脐往,地道東北人休吠。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像业簿,于是被迫代替她去往敵國(guó)和親瘤礁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容