自建iOS构建流水线建设核心原理剖析

简介: 文章主要从iOS打包机远程构建的角度分析,整体链路脚本涉及的shell、ruby、security指令、xml以及iOS工程化相关知识,文章通过一个远程构建流程简单并重点的讲解了如何规避本地打包环境下的小的修改出包存在的大量人工操作,如何动态化配置证书、版本号等信息以及内测分发方式的避坑点。

一、背景

1.1 问题

移动端开发交付项目中,由于交付团队技术沉淀参差不齐,开发流程极不规范,经常出现这打包在本地,甚至是集中在某个外包开发自己,这样的方式存在以下问题:

  1. 不安全:代码、证书、签名泄漏风险
  2. 低效:环境不可靠,稳定,打包效率慢,小的改动打包可能涉及到大量的人工操作
  3. 低质量:受本地环境如缓存、分支、配置等因素影响较大,出包质量参差不齐
  4. 协同性低:基本集中在某个人身上,高度依赖
  5. 版本管理差:个人记录,归档基本不存在
  6. 其他(持续集成、安装分发、权限控制没法做····)

1.2 目标

也是由于存在以上诸多问题,所以,统一的构建流水线是必须的,至少要实现云端统一构建,支持证书管理、版本管理、权限管控、安装分发等能力

1.3 方案

想要实现流水线构建,需要具备以下基本的环境:

  1. 公网访问
  2. 打包机(Android linux环境即可、iOS需要xcode环境)

1.3.1 公网访问

这个是交付项目的客观存在,所以不可能直接面向集团内部资源,我们这里就直接考虑入口在GTS统一工作台的大禹研发域

1.3.2 打包机

  • Android,linux环境即可,我们平时时候的流水线jenkins服务都运行在linux环境上,所以Android没有太大的问题(Android由于难度较低,本文不做分析。)
  • iOS,需要xcode环境,iOS生态是比较封闭的,所以目前调研的有3种方案:
  1. mac机器,需要解决机器的托管以及外网访问问题
  2. mac虚拟技术,有一定的技术壁垒,成本较高
  3. 技术合作

决策:技术合作是成本最低,见效最快的方式。

合作方给我们提供了非常友好的对接方式,他们提供xcode运行环境,剩下的我们自己想怎么玩就怎么玩。

二、设计

想要设计一个移动端流水线,当然不能简单的打个包就行了,我们需要解决的是上面提到的各种问题,以及要基于流水线以及移动端产品的特性而开发一些额外的功能

2.1 功能大图

这里功能简单罗列构建相关核心功能点

项目

说明

证书管理

证书的上传、下载、访问权限管理

版本管理

构建记录

构建code与源码commit映射

产物分发

支持扫码安装

支持访问权限配置

支持有效期配置

构建参数

  1. Version 版本号
  2. 唯一的安装ID,一般用于一机多装
  3. AppName 名称
  4. ad-hoc,dev,enterprise,app store
  5. 环境、日志等其他信息


2.2 环境准备

在正式的开始构建前,这里先解决两个技术点:

2.2.1. 合作方的调用链路;

合作方案调用方式

2.2.2 .code specs的访问权限

大部分iOS开发已经是基于pods管理的组件化的方案,所以需要打通私有specs仓库和公共仓库的访问

代码以及仓库访问权限管理

2.3 构建思路

构建步骤主要为以下清单:

由于资源都是在自己的服务器上,所以这里的步骤跳过了所需要的资源的拉取以及xcode,pods版本的切换

步骤

项目

说明

1

资源拉取

工程源码、证书、profile文件

2

xcode、pods版本切换

根据工程实际情况选择

3

证书安装

核心:证书文件,必须在当前机器安装才能使用

4

profile描述文件安装

核心:描述文件,必须在当前机器安装才能使用

5

xcodeproj修改配置

核心:修改version,bundleId,app_name,证书、描述文件等信息

6

额外的插件安装

比如mPaaS,需要安装mPaaS相关的资源,这个也是基于项目使用了mPaaS插件,所以也就增加了这个的扩展,一般项目可以在配置单默认关闭即可

7

pods update/install

核心:依赖拉取

8

archive

核心:xocdebuild 构建

9

exportArchive

核心:导出ipa

10

deploy

核心:安装分发配置

三、核心点剖析

安全需要,为了讲清楚核心点,以下代码为部分核心代码,并非完整代码,额外需要处理大量的判断逻辑比如:cert和profile以及bundleId、打包类型一致性;证书、描述文件大量时候的删除重装逻辑等。

3.1 证书安装

iOS构建的证书是安装在OSX系统的钥匙链里面,需要使用系统的`security`指令执行创建和访问配置:

#1. 创建security create-keychain -p$keychain_password$keychain_name#2. 解锁security unlock-keychain -p$keychain_password$keychain_name#3. 导入security import $p12_path-k$keychain_name-P$p12_password-A#4. 设置访问权限security set-key-partition-list -S apple-tool:,apple: -k$keychain_password$keychain_name#5. 更改钥匙串配置security set-keychain-settings $keychain_name


3.2 privosion profile描述文件安装

这个描述文件安装就比较简单,复制到指定目录

`${HOME}/Library/MobileDevice/Provisioning\ Profiles`即可,同时修改文件名为profile对应的uuid
cp$profile_file${HOME}/Library/MobileDevice/Provisioning\ Profiles/${INSTALL_PROFILE_UUID}.mobileprovision

3.3 xcodeproj修改配置

这一步是个难点,也是个核心大头,由于xcode工程配置用的ruby脚本管理,所以这里的配置也是由ruby进行修改,大体流程如下:

  1. 找到对应target
  2. 修改cert和profile
  3. 修改bundle_id、app_name、build、version_code
  4. 修改签名机制手动挡
#读出project信息project=Xcodeproj::Project.open(project_path)
#检索targetproject.targets.eachdo |target|
#读取config对象config=target.build_configuration_list[configuration]
#对config配置config.build_settings["CODE_SIGN_STYLE"] ="Manual"config.build_settings["PRODUCT_BUNDLE_IDENTIFIER"] =bundle_idconfig.build_settings["DEVELOPMENT_TEAM"] =team_idconfig.build_settings["CODE_SIGN_IDENTITY"] =full_cert_nameconfig.build_settings["PROVISIONING_PROFILE_SPECIFIER"] =profile_nameend

3.4 pod install

podspec 有墙的因素,导致很多github specs以及墙外资源经常性拉取失败,所以在pods install这个阶段做了三种优化:

  1. 使用自建/国内specs镜像
  2. Pods目录上传到代码库,跳过pods install阶段
  3. 使用缓存机制,对Pods资源缓存

3.5 Archive

3.5.1 首先clean

# 编译前清理工程xcodebuild clean -workspace${workspace_name}.xcworkspace \
-scheme${scheme_name} \
-configuration${build_configuration}

3.5.2 执行archive

xcodebuild archive -workspace${workspace_name}.xcworkspace \
-scheme${scheme_name} \
-configuration${build_configuration} \
-archivePath${export_archive_path} \
CHANNEL=true \
GCC_PREPROCESSOR_DEFINITIONS='$(inherited) CUST_NUM1=99'

可以通过GCC_PREPROCESSOR_DEFINITIONS配置自定义的运行时变量

3.6 exportArchive ipa阶段

执行真正的exportArchive前,需要根据参数`生成export_options_plist文件`

#1. 根据参数生成export_options_plist文件/usr/libexec/PlistBuddy -c"Add :compileBitcode bool ${compileBitcode}"$export_options_plist_path/usr/libexec/PlistBuddy -c"Add :method string ${method}"$export_options_plist_path/usr/libexec/PlistBuddy -c"Add :provisioningProfiles:"$export_options_plist_path### 这里是做了个扩展点echo"$extension_export_plist" | while read line
do/usr/libexec/PlistBuddy -c"$line"$export_options_plist_pathdone



#2. 执行exportArchivexcodebuild  -exportArchive \
-archivePath${export_archive_path} \
-exportPath${export_ipa_path} \
-exportOptionsPlist${export_options_plist_path} \
-allowProvisioningUpdates

3.7 Deply 内测分发

这个阶段又叫内测分发,iOS 打包产物想要安装到iOS设备上,比Android复杂很多,除了testflight和App Store正常安装外,日常测试也是需要安装,我们这里做了分发功能,通过扫描二维码即可安装(遵循设备注册和企业包灯等的安装限制)

核心点:

itms-services:///?action=download-manifest&url=https://resource.dayu.work/build-packages/xxx/ios-test.plist


启用一个itms-services标签,指向一个plist描述文件,plist格式如下,有几个点必须注意,严格遵守:

  1. itms-services标签下的url链接协议必须是https
  2. itms-services标签下的url链接不能有特殊字符,否则会导致plist文件解析失败,比如'%'不能有
<?xmlversion="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plistversion="1.0"><dict><key>items</key><array><dict><key>assets</key><array><dict><key>kind</key><string>software-package</string><key>url</key><string>https://xxxx.com/xxxxxxx/download</string></dict></array><key>metadata</key><dict><key>bundle-identifier</key><string>com.dayu.buildios</string><key>bundle-version</key><string>1.0.0-MTL-SNAPSHOT</string><key>kind</key><string>software</string><key>title</key><string>流水线测试包</string></dict></dict></array></dict></plist>


总结

本篇文章主要是对IOS构建做了一个从xcodebuild 基础命令的,包括流水线构建流程做了个剖析,感兴趣的可以自行尝试,目前市面也有很多比较成熟的产品,比如fastlane,托管式的集成方式,甚至不用管理证书,但是涉及到一些扩展或者是修改,灵活性就不那么强了,所以懂了原理之后,想怎么玩看读者自己了。

相关文章
|
2月前
|
存储 运维 安全
iOS加固原理与常见措施:保护移动应用程序安全的利器
iOS加固原理与常见措施:保护移动应用程序安全的利器
28 0
|
9天前
|
JSON 运维 Kubernetes
云效产品使用报错问题之流水线中配置了AppStack,构建时下载的制品内容为json字符串,如何解决
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
9天前
|
存储 编解码 JSON
利用SwiftUI构建高效iOS天气应用
【4月更文挑战第21天】 在本文中,我们将深入探讨如何运用SwiftUI框架打造一个响应迅速且用户友好的iOS天气应用程序。我们将重点放在利用SwiftUI的声明式语法简化界面开发,并通过结合Core Location和Networking APIs实现实时天气数据的获取与展示。文章将详细阐述整个开发过程,包括API集成、数据模型设计、用户界面布局以及动态适配不同屏幕尺寸的策略。
|
9天前
|
敏捷开发 安全 Java
云效产品使用常见问题之不知道自定义镜像构建是作用在整个流水线,还是只作用在一个卡片如何解决
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
28天前
|
开发工具 Swift iOS开发
利用SwiftUI构建动态用户界面:iOS开发新范式
【4月更文挑战第3天】 随着苹果不断推进其软件开发工具的边界,SwiftUI作为一种新兴的编程框架,已经逐渐成为iOS开发者的新宠。不同于传统的UIKit,SwiftUI通过声明式语法和强大的功能组合,为创建动态且响应式的用户界面提供了一种更加简洁高效的方式。本文将深入探讨如何利用SwiftUI技术构建具有高度自定义能力和响应性的用户界面,并展示其在现代iOS应用开发中的优势和潜力。
|
29天前
|
jenkins 持续交付
Jenkins构建简单流水线
Jenkins构建简单流水线
12 0
|
2月前
|
数据安全/隐私保护 开发者 iOS开发
iOS-打包上架构建版本一直不出现/正在处理/自动消失
iOS-打包上架构建版本一直不出现/正在处理/自动消失
26 0
|
2月前
|
Java 测试技术 API
云效流水线构建gradle项目失败提示gradle版本过低如何解决
云效(CloudEfficiency)是阿里云提供的一套软件研发效能平台,旨在通过工程效能、项目管理、质量保障等工具与服务,帮助企业提高软件研发的效率和质量。本合集是云效使用中可能遇到的一些常见问题及其答案的汇总。
36 0
|
2月前
|
机器学习/深度学习 测试技术 API
iOS系统下轻松构建自动化数据收集流程
iOS系统下轻松构建自动化数据收集流程
27 0
|
3月前
|
安全 前端开发 数据安全/隐私保护
【教程】 iOS混淆加固原理篇
本文介绍了iOS应用程序混淆加固的缘由,编译过程以及常见的加固类型和逆向工具。详细讨论了字符串混淆、类名、方法名混淆、程序结构混淆加密等加固类型,并介绍了常见的逆向工具和代码虚拟化技术。