Skip to content

iOS 应用自动上传蒲公英教程

本文将介绍如何使用 Python 脚本,自动将打包生成的 .ipa 文件上传至 蒲公英 (Pgyer) 平台,方便团队分发和测试。


📌 前置准备

  1. 安装 Python 3
  2. macOS 自带 Python,推荐使用 Python 官网 安装最新版本。

  3. 安装依赖库 bash pip install requests

  4. 注册蒲公英账号

  5. 登录 蒲公英官网
  6. 用户中心 获取:
    • USER_KEY
    • API_KEY

📂 项目结构

假设脚本文件为 pgyer_upload.py,目录结构如下:

project/
├── ipa/                 # 存放打包好的 ipa 文件
├── pgyer_upload.py      # 上传脚本

💻 核心功能说明

1. 自动查找最新 IPA 文件

会自动在 ipa/ 文件夹中找到最新打包的 .ipa 文件。


2. 获取上传凭证 (Token)

调用蒲公英 API 获取上传凭证。


3. 执行上传

使用上传凭证将 .ipa 文件上传到蒲公英服务器。


4. 验证上传结果

检查上传是否成功,确保文件在蒲公英平台可用。


🚀 使用方法

  1. 修改脚本中的配置信息:
PGY_DOWNLOAD_URL = 'https://www.pgyer.com/xxxxxx'
USER_KEY = '你的UserKey'
API_KEY = '你的ApiKey'
  1. 执行脚本:
python pgyer_upload.py
  1. 输出示例:
找到 IPA 文件: /Users/xxx/project/ipa/app-20250925.ipa

=========== 获取蒲公英上传 Token ===========
返回的 Token 数据: {...}

=========== 上传 IPA 文件 ===========
✅ 上传成功

=========== 校验上传信息 ===========
✅ 校验成功

📜 完整脚本代码

import os
import requests
import webbrowser
import time

# 蒲公英配置(UAT)
PGY_DOWNLOAD_URL = 'https://www.pgyer.com/xxxxxx'
USER_KEY = ''
API_KEY = ''

# 路径设置
BASE_DIR = os.path.abspath(os.path.dirname(__file__))  # 当前目录
EXPORT_DIR = BASE_DIR
EXPORT_FOLDER = 'ipa'


class PgyerUploader:

    def __init__(self):
        self.ipa_path = None

    def upload(self):
        # 自动找到最新的 IPA 文件并上传到蒲公英
        ipa_path = self.find_latest_ipa(EXPORT_DIR, EXPORT_FOLDER)
        if not ipa_path:
            print("❌ 没有找到 IPA 文件")
            return

        print(f"找到 IPA 文件: {ipa_path}")

        # 获取上传凭证
        token = self.get_token()
        if not token:
            return

        # 上传文件
        self.perform_upload(ipa_path, token)

    def find_latest_ipa(self, base_dir, folder_name):
        ipa_folder = os.path.join(base_dir, folder_name)
        if not os.path.exists(ipa_folder):
            print(f"❌ 没有找到 {ipa_folder} 目录")
            return None

        ipa_files = [f for f in os.listdir(ipa_folder) if f.endswith('.ipa')]
        if not ipa_files:
            print("❌ 该目录下没有找到 IPA 文件")
            return None

        latest_ipa = max(ipa_files, key=lambda f: os.path.getmtime(os.path.join(ipa_folder, f)))
        return os.path.join(ipa_folder, latest_ipa)

    def get_token(self):
        print("\n=========== 获取蒲公英上传 Token ===========")
        url = 'https://www.pgyer.com/apiv2/app/getCOSToken'
        data = {
            'uKey': USER_KEY,
            '_api_key': API_KEY,
            'buildType': 'ios',
        }

        r = requests.post(url, data=data)
        if r.status_code == 200:
            res_data = r.json().get("data")
            print("返回的 Token 数据:", res_data)
            return res_data
        else:
            print("获取 Token 失败,状态码:", r.status_code)
            return None

    def perform_upload(self, ipa_path, token):
        print("\n=========== 上传 IPA 文件 ===========")

        url = token["endpoint"]
        data = token["params"]

        with open(ipa_path, 'rb') as f:
            files = {'file': f}
            r = requests.post(url, data=data, files=files)

        if r.status_code == 204:
            print("✅ 上传成功")
            self.build_info(token["key"])
        else:
            print("❌ 上传失败,状态码:", r.status_code)

    def build_info(self, key):
        time.sleep(5)
        print("\n=========== 校验上传信息 ===========")
        url = 'https://www.pgyer.com/apiv2/app/buildInfo'
        data = {
            'buildKey': key,
            '_api_key': API_KEY,
        }

        r = requests.get(url, params=data)
        if r.status_code == 200:
            res_json = r.json()
            if res_json.get("code") == 0:
                print("✅ 校验成功")
            else:
                print("❓ 验证中:", res_json.get("message"))
        else:
            print("❌ 校验失败,状态码:", r.status_code)


if __name__ == '__main__':
    uploader = PgyerUploader()
    uploader.upload()