ios重签名shell脚本_Mac系统下应用重签名技术

概述

做为一个项目驱动的公司,在管理APP描述文件的时候,时常会遇到描述文件过期的问题,产生的影响是导致客户端应用无法使用,这时候用户会不知所措,给用户的体验造成影响,甚至会影响APP的流量。而大多数解决方案,是利用市场上的重签名工具对应用重新签名发布,或者利用Xcode重新打包发布,这对开发者来说极不友好。我们绝不能亡羊补牢,必须在风险到来前提前准备防御,在用户无感知的情况下修复问题。出于此目的,应用重签名技术便有了它的意义,如果你是还没有研究过或者正在研究重签名技术的话,那这篇文章会非常适合你。

前置条件

iOS应用重签名具有一定的前置条件和软件依赖,并不是跨平台的,至少这套方案不能在 Window 上使用。

依赖条件

MacOS操作系统

Apple开发者账号

/usr/libexec/PlistBuddy (MacOS自带)

security (MacOS自带)

codesign (MacOS自带)

zip

unzip

上述依赖条件为系统软件,如果 zip 和 unzip 软件不存在的话可以通过 HomeBrew 进行安装.

brew install zip;

brew install unzip;

iPA 简述

做为一个移动开发者应该知道 Android 的应用安装包为*.apk,而iOS的应用安装包则为*.ipa,事实上这些安装包都是可以通过unzip命令进行解压缩的压缩包,提取出来的文件是应用所需要的资源文件、应用配置文件、应用描述文件和应用二进制文件等,其中应用描述文件则是我们这次操作的目标。

除了应用描述文件需要关注外,在iPA中还存在一类应用,那就是 appex。这类应用为宿主应用的拓展应用,appex同样存在自己的描述文件,如果宿主应用描述文件更新成功,但是appex应用没有更新描述文件的话,同样是签名失败的。

总结,如果应用需要重签名的话,则需要判断是否存在appex应用,如果存在则需要对每一个 appex 目录进行重签名,最后对整体目录进行重签名,如果不存在的话则只需要对主目录进行重签名即可。

我们可以在爱思助手下载应用的iPA包,然后通过可视化软件进行解压。

描述文件中 BundleId 的能力

每一个 BundleId 都会有对应的 Capabilities,签名目标所拥有的能力一定不能比当前新描述文件所具备的能力少,如果新描述文件所具备的能力少于目标签名的对象,则签名同样失败。

重签名核心操作

重签名的核心操作是 codesign,该命令是 MacOS 下自带的命令,主要用于代码签名。

签名命令:

codesign -f -s "DEVELOPER_TEAM" "PLISTFILE_PATH" "SIGN_DIRECTORY"

其中 -f 代表 force 强制更新,-s 代表 sign。

-f, --force

When signing, causes codesign to replace any existing signature on the path(s) given. Without

this option, existing signatures will not be replaced, and the signing operation fails.

-s, --sign identity

Sign the code at the path(s) given using this identity. See SIGNING IDENTITIES below.

操作简述

分析完毕后,设计思路应该是:

解压目标

ipa包到临时目录

将应用下的embedded.mobileprovision替换为新的描述文件

将新描述文件转换为info.plist文件到临时目录

从上面操作后的info.plist中提取TeamName, Entitlements信息

最后利用重签名的核心操作对目录进行重签名

上述过程中的第2,3,4,5步,如果appex应用存在也需要重新同样的操作,如果不存在则不需要执行

签名完毕后,利用zip命令对应用重新打包成ipa文件

删除临时目录生成的垃圾文件

到此为止重签名的操作就完成了,我们利用 Shell 脚本将操作实现。

第一步:创建临时目录

创建临时目录,用来保存操作过程中产生的垃圾

# 创建临时目录

ROOT_PATH=$(pwd)

DIR_TMP_PATH="${ROOT_PATH}/temp"

# 删除旧目录并创建临时目录

rm -rf $DIR_TMP_PATH

mkdir $DIR_TMP_PATH

第二步:解压目标iPA

将需要重签名ipa包目录,解压到临时文件

# 从用户输入的参数中获取 iPA 地址

PARAM_IPA_PATH=$1

# 解压到临时目录

unzip -d $DIR_TMP_PATH $PARAM_IPA_PATH

第三步:封装重签名操作过程

无论是宿主应用还是拓展应用,其重签名的操作过程其实是一样的,我们把其封装成方法

# 从描述文件中提取完整plist文件

_getPlistFile(){

local _path=$1

local _name=$2

local originMobileprovisionPath="${_path}/embedded.mobileprovision"

local tempEntitle="${DIR_ENTITLEMENTS_TMP_PATH}/${_name}_temp.plist"

local entitle="${DIR_ENTITLEMENTS_TMP_PATH}/${_name}.plist"

security cms -D -i "$originMobileprovisionPath" > "${tempEntitle}"

# 提取 Entitlements 字段

/usr/libexec/PlistBuddy -x -c 'Print:Entitlements' $tempEntitle > $entitle

}

# 重签名拓展应用

reSign(){

local _path=$1

local _appexName=$2

local _tmpMbArray=(${_appexName/./ })

local _tmpMbName=${_tmpMbArray[0]}

# 把新的描述文件替换旧版描述文件

local _mbPath="${_path}/embedded.mobileprovision";

rm -rf _mbPath

for index in $(seq 0 ${#PARAM_APPEXMOBILEPROVISION[@]})

do

local appexMb=${PARAM_APPEXMOBILEPROVISION[index]}

local _tmpStrArray=(${appexMb })

local last=${#_tmpStrArray[@]}

((last-=1))

if [ $last -ge 0 ]

then

local _newAppexMb=${_tmpStrArray[last]}

if [[ $_newAppexMb =~ $_tmpMbName ]];

then

# 复制新的文件到目标目录

cp $appexMb $_mbPath

break

fi

fi

done

_getPlistFile $_path $_tmpMbName

local _plistPath="${DIR_ENTITLEMENTS_TMP_PATH}/${_tmpMbName}.plist";

echo $PARAM_DEVELOPTEAM

echo $_plistPath

echo $_path

codesign -f -s "${PARAM_DEVELOPTEAM}" --entitlements "${_plistPath}" "${_path}"

}

第四步:递归遍历所有目录

我们需要对所有文件夹进行判断,并且进行重签名操作

# 递归遍历目录

recursivePath(){

local _path=$1;

for item in $(ls "$_path")

do

local subPath="${_path}/${item}";

if [[ ${item} =~ '.appex' ]];

then

# 对应用拓展进行重签名

reSign "${subPath}" $item

else

if [ -d "$subPath" ];

then

recursivePath $subPath

fi

fi

done

}

# 宿主应用进行重签名操作

reSign "宿主应用描述文件路径" "宿主应用根目录"

第五步:打包新的iPA包

重签名操作完成后,我们新的目录重新进行压缩打包。

cd "新的文件目录中,必须到 /Payload 目录级"

zip -r "New.ipa" ./Payload

mv ./New.ipa "输出目录"

第六步:删除垃圾文件

所有操作完成后,就可以删除垃圾文件,这样我们的重签名操作就完成了。

# 移除垃圾文件

rm -rf $DIR_TMP_PATH

拓展延伸

为什么需要设计 Shell 脚本,因为方便和 Jenkins 等平台对接,我们利用脚本可以在服务端进行定时判断,可以在应用过期一个月前提前通知到开发者,这样开发者只需要提前一个月上传新的描述文件,系统将会自动完成更新。

利用 PlistBuddy 命令可以设计出更多个性化的功能,例如可以自定义版本号,APP名称等。

你可能感兴趣的:(ios重签名shell脚本)