Automating iOS Build and Distribution with Jenkins and Python

This guide explains how to configure Jenkins with necessary plugins, install iOS certificates, and use a Python script to automate cleaning, building, packaging, and uploading an iOS .ipa to Pgyer, enabling quick distribution to internal testers.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Automating iOS Build and Distribution with Jenkins and Python

Environment configuration includes installing Jenkins plugins (GitLab Plugin, Gitlab Hook Plugin, Xcode integration, Keychains and Provisioning Profiles Management), installing Xcode, Python 3.6, and preparing iOS certificates and provisioning profiles.

In Jenkins, create a new project to pull the source code, then install the iOS certificate and provisioning profile by double‑clicking them to add to the macOS keychain and Xcode.

The following Python script automates the clean, build, packaging, and upload of the .ipa to Pgyer. It defines paths, runs xcodebuild, creates the Payload folder, zips it, renames it to .ipa, and posts it to the Pgyer API.

import os
import subprocess
import requests
import webbrowser

# .app文件路径
APP_FILE_FULL_PATH = 'xxx.app'
#存放ipa路径
PAYLOAD_PATH = '/Users/你自己电脑用户名称/Desktop/auto_pack/Payload'
PACK_BAG_PATH = '/Users/你自己电脑用户名称/Desktop/auto_pack/ProgramBag'
# 蒲公英项目的页面地址
OPEN_URL_PATH = 'xxxxxx'
# jenkins--iOS项目目录
WORKSPACE_PATH = 'xxxxxx'
# iOS项目名称
WORKSPACE_NAME = 'xxxxxx'
# Scheme名称
SCHEME_NAME = 'xxxxxx'
# 蒲公英ApiKey
API_KEY = "xxxxxx"

#编译打包流程
def build_ipa():
    # 切换到iOS项目目录
    os.chdir(WORKSPACE_PATH)
    clean_cmd = 'xcodebuild clean -workspace %s.xcworkspace -scheme %s' % (WORKSPACE_NAME, SCHEME_NAME)
    subprocess.call(clean_cmd, shell=True)
    print("
*************** clean完成 *********************
")
    # 编译iOS项目
    build_cmd = 'xcodebuild -workspace %s.xcworkspace -scheme %s build' % (WORKSPACE_NAME, SCHEME_NAME)
    print("
*************** 开始编译 *********************
")
    subprocess.call(build_cmd, shell=True)
    # 删除之前打包的ProgramBag文件夹
    subprocess.call(["rm", "-rf", PACK_BAG_PATH])
    # 创建PayLoad文件夹
    mk_dir(PAYLOAD_PATH)
    # 将app拷贝到PayLoadPath路径下
    subprocess.call(["cp", "-r", APP_FILE_FULL_PATH, PAYLOAD_PATH])
    # 创建packBagPath的文件夹
    subprocess.call(["mkdir", "-p", PACK_BAG_PATH])
    # 将PayLoadPath文件夹拷贝到packBagPath文件夹下
    subprocess.call(["cp", "-r", PAYLOAD_PATH, PACK_BAG_PATH])
    # 删除PayLoadPath文件夹
    subprocess.call(["rm", "-rf", PAYLOAD_PATH])
    # 切换到当前目录
    os.chdir(PACK_BAG_PATH)
    # 压缩packBagPath文件夹下的PayLoadPath文件夹
    subprocess.call(["zip", "-r", "./Payload.zip", "."])
    print("
*************** 打包成功 *********************
")
    # 将zip文件改名为ipa
    subprocess.call(["mv", "payload.zip", "Payload.ipa"])
    # 删除payLoad文件夹
    subprocess.call(["rm", "-rf", "./Payload"])

# 创建PayLoad文件夹
def mk_dir(payload_path):
    is_exists = os.path.exists(payload_path)
    if not is_exists:
        os.makedirs(payload_path)
        print(payload_path + '创建成功')
        return True
    else:
        print(payload_path + '目录已经存在')
        return False

#上传蒲公英
def upload_ipa(ipa_path):
    if ipa_path == '':
        print("
*************** 没有找到对应上传的IPA包 *********************
")
        return
    else:
        print("
*************** 开始上传到蒲公英 *********************
")
        url = 'https://www.pgyer.com/apiv2/app/upload'
        data = {
            '_api_key': API_KEY,
            'buildInstallType': '2',
            'buildPassword': '',
            'buildUpdateDescription': ""
        }
        files = {'file': open(ipa_path, 'rb')}
        requests.post(url, data=data, files=files)

def open_download_url():
    webbrowser.open(OPEN_URL_PATH, new=1, autoraise=True)
    print("
*************** 更新成功 *********************
")

if __name__ == '__main__':
    build_ipa()
    upload_ipa('%s/Payload.ipa' % PACK_BAG_PATH)
    # open_download_url()

After execution, the IPA is uploaded to Pgyer, which generates a QR code that can be shared with internal testers for easy installation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

iOSPythonCI/CDAutomationJenkinsPgyer
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.