python一键实现apk编译打包、上传蒲公英、企业微信机器人提醒

编译脚本组成

1681351227078.png

1、buildApk.py:位于根目录,调用不同平台shell的gradlew clean 和 根据用户选择gradlew assembleRelease或者 gradlew assembleDebug ,调用UploadUtil.uploadPuGongYing(vSysInfo=vSysInfo)上传到蒲公英平台
2、upload_pgyer.py:蒲公英官方api 2.0上传apk,获取上传后的apk信息
3、upload.py: 调用蒲公英官方上传api, 将获取到apk信息发送到企业微信群机器人提醒
4、buildUpdateMsg.txt:更新日志,此内容会更新到蒲公英更新描述和企业微信群内

编译环境

1、安装python 3版本
2、使用pip install requests库
3、执行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 = """
    请输入编译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("*********************************编译开始**********************************")
    #删除以前的编译文件
    # 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("开始执行 gradlew clean")
    systemInfo = platform.system().lower()
    print("编译系统:%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("执行 gradlew clean结束")
        print("开始执行 gradlew assemble")
        # assembleResult = subprocess.call([commond, "assemble" + vSysInfo],shell=True)
        assembleResult = os.system(commond + " assemble" + vSysInfo)
        # assembleResult = 0
        if (assembleResult == 0):
            print("执行gradlew assemble成功")
            print("*********************************编译结束**********************************")
            UploadUtil.uploadPuGongYing(vSysInfo=vSysInfo)
        else:
            print("执行gradlew assemble失败")
    else:
        print("执行gradlew 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', # 需要上传的应用类型,ios 或 android
    'buildInstallType': install_type, # (选填)应用安装方式,值为(1,2,3,默认为1 公开安装)。1:公开安装,2:密码安装,3:邀请安装
    'buildPassword': password, # (选填) 设置App安装密码,密码为空时默认公开安装
    'buildUpdateDescription': update_description, # (选填) 版本更新描述,请传空字符串,或不传。
  }
  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('服务器暂时无法为您服务', 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: 应用安装方式,值为(1,2,3)。1:公开,2:密码安装,3:邀请安装。默认为1公开
    :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("上传成功,正在获取包处理信息,请稍等...")
            _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('服务器暂时无法为您服务', 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):
    """
    检测应用是否发布完成,并获取发布应用的信息
    """
    time.sleep(3) # 先等个几秒,上传完直接获取肯定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   应用正在解析、1247 应用正在发布中
        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="企业微信机器人webhook地址"
buildTime = ""
userBuild = ""
#读取更新内容
def readUpdateMsg():
  f = open('buildUpdateMsg.txt', 'r', encoding='utf-8')
  try:
    lines = f.readlines()
    # print(lines)
    return lines
  finally:
    f.close()
  pass

#发送企业微信机器人消息
def send_wechat_msg(content, webhook_url= "你的机器人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

#上传蒲公英平台
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结束**********************************")
      _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 = """
      应用更新提醒
      您的应用上传了新版本
      应用名称:{buildName}
      应用类型:{buildPlatform}
      版本信息:{buildVersion}(Build {buildVersionNo})
      应用大小:{buildFileSize}M
      安装密码:{pgyerPassword}
      编译系统:{buildSystem}
      编译用户: {userBuild}
      编译类型:{vSysInfo}
      编译时间: {buildTime}
      更新时间:{buildUpdated}
      更新内容:{update_description}
      点击查看应用:[{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("*********************************企业微信提醒开始**********************************")
      status_code, text = send_wechat_msg(content=content, webhook_url=webhook_url)
      print("微信提醒", status_code, text)
      print("*********************************企业微信提醒结束**********************************")
    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("编译文件错误")
  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("编译时间:%s" %buildTime)
    userBuild = os.getlogin()
    print("编译用户名:%s" %userBuild)
    updateMsgs = readUpdateMsg()
    update_description = ""
    print("*********************************更新内容开始**********************************")
    for msg in updateMsgs:
      update_description += msg
      print(msg)
    print("*********************************更新内容结束**********************************")
    print("*********************************上传apk开始**********************************")
    PgyerUtil.upload_to_pgyer(
      path = app_path,
      api_key = pgyer_api_key,
      password=pgyer_password,
      update_description=update_description,
      callback=upload_complete_callback
    )

#编译脚本执行入口
def main():
  uploadPuGongYing()
if __name__ == "__main__":
  main()

注意 apk文件名称定义,目的脚本获取到编译时间及编译类型

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"
            }
        }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容