文档章节

iOS批量自动打包和部署(Ⅲ):重新签名和自动部署

hejunbinlan
 hejunbinlan
发布于 2016/07/29 17:45
字数 2785
阅读 878
收藏 2
点赞 1
评论 4

本篇为这个系列的最后一篇,主要会讲重新签名和自动部署的问题。通过前面的步骤已经能够打包并签名了,现在回到系列开始时提到的问题:如何能够快速复制非常相似但又不同的包呢?其实,重新签名就能够做到!

重新签名和授权机制

我们知道苹果在打包的最后步骤就是进行签名,如果对于一个已经签名的包,我们还可以进行重新签名,签名的命令主要是codesign。例如(摘自代码签名探析):

$ codesign -s 'iPhone Developer: Thomas Kollbach (7TPNXN7G6K)' Example.app  设置签名

如果你想为某一个 app 程序包重新设置签名,那么这个工具就很有用了。为了重新设置签名,你必须带上 -f 参数,有了这个参数,codesign 会用你选择的签名替换掉已经存在的那一个:

$ codesign -f -s 'iPhone Developer: Thomas Kollbach (7TPNXN7G6K)' Example.app  重新签名
$ codesign -vv -d Example.app 会列出一些有关 Example.app的签名信息    $ codesign --verify Example.app  会验证签名是否完好,若无任何输出则说明签名完好

除了重新签名的命令,还需要知道的是entitlements授权机制。授权机制决定了哪些系统资源在什么情况下允许被一个应用使用,即沙盒的配置列表。授权机制也是按照 plist 文件格式来列出的,Xcode 会将这个文件作为 –entitlements 参数的内容传给 codesign ,这个文件内部格式如下:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  
<plist version="1.0">  
<dict>  
    <key>application-identifier</key>
    <string>7TPNXN7G6K.ch.kollba.example</string>
    <key>aps-environment</key>
    <string>development</string>
    <key>com.apple.developer.team-identifier</key> 
    <string>7TPNXN7G6K</string>
    <key>com.apple.developer.ubiquity-container-identifiers</key>
    <array>
            <string>7TPNXN7G6K.ch.kollba.example</string>
    </array>
    <key>com.apple.developer.ubiquity-kvstore-identifier</key>
    <string>7TPNXN7G6K.ch.kollba.example</string>
    <key>com.apple.security.application-groups</key>
    <array>
            <string>group.ch.kollba.example</string>
    </array>
    <key>get-task-allow</key>
    <true/>
</dict>  
</plist>  

在 Xcode 的 Capabilities 选项卡下选择一些选项之后,Xcode 就会生成这样一段 XML。 Xcode 会自动生成一个 .entitlements 文件,然后在需要的时候往里面添加条目。当构建整个应用时,这个文件也会提交给 codesign 作为应用所需要拥有哪些授权的参考。这些授权信息必须都在开发者中心的 App ID 中启用,并且包含在配置文件中,稍后我们会详细讨论这一点。在构建应用时需要使用的授权文件可以在 Xcode build setting 中的 code signing entitlements 中设置。

上面两段主要摘自《代码签名探析》,这是为了方便解释后面的重新签名脚本。

重新签名的实例

为了达到对一个app进行快速换皮的目的,我的设计思路如下图(本篇所有的Demo在这里)):

先自动打包生成一个母包,然后跑脚本对母包进行重新签名得到一个个子包。继续前面的PackageExample例子,PackageExample的bundleid为com.vienta.packageExample,其作为母包,我又重新申请了两个bundleid,分别为com.vienta.packageExampleSoncom.vienta.packageExampleDaughter,作为重新签名后的子包。本例子主要通过通过换icon来反映”换皮”。

实例的Resign-ipa文件夹目录结构如下图:

templates文件夹中存放的是和授权文件相关的配置文件,build文件夹主要存放最后被重新签名的包,module目录下存放重签名的配置文件、资源文件和描述文件等。这里的思路是遍历module文件夹下的内容,然后根据内容重新签名母包,将得到的包放到build,例子中是两个,实际如果版本非常多,只需要向module增加文件夹及配置内容即可。

resign.sh为重签名的脚本,内容也不算多:

#!/bin/bash

for file2 in `ls -a ./module`
do
    if [ x"$file2" != x"." -a x"$file2" != x".." -a x"$file2" != x".DS_Store" ]; then
        echo $file2

        #Conf file
        CONF=./module/$file2/resign.conf

        echo $CONF

        #Datetime 
        NOW=$(date +"%Y%m%d_%s")

        #Load config
        if [ -f ${CONF} ]; then
            . ${CONF}
        fi

        #Temp
        TEMP="temp"
        if [ -e ${TEMP} ]; then
            echo "ERROR: temp already exists"
            exit 1
        fi

        #Check app ID
        if [ -z ${APP_ID} ]; then
            echo "ERROR: missing APP_ID"
            exit 1
        fi

        echo ${APP_ID}

        #Create build dir 
        if [[ ! -d ${BUILD_PATH} ]]; then
            mkdir ${BUILD_PATH}
        fi

        #Copy mother package
        if [[ ! -f  "../Package/ipa/QA/packageExample.ipa" ]]; then
            echo "mother package not exists"
            exit 1
        fi
        cp ../Package/ipa/QA/packageExample.ipa ./module/$file2${ASSETS_PATH}/packageExample.ipa

        #Unzip the mother ipa
        echo "Unzip ipa"
        unzip -q ./module/$file2${ASSETS_PATH}${IPA_NAME}.ipa -d ${TEMP}

        #Remove old Codesignature
        echo "Remove old CodeSignature"
        rm -r "${TEMP}/Payload/${APP_NAME}.app/_CodeSignature" "${TEMP}/Payload/${APP_NAME}.app/CodeResources" 2> /dev/null | true

        #Replace embedded mobil provisioning profile
        echo "Replace embedded mobile provisioning profile"
        cp "./module/$file2${ASSETS_PATH}${PROFILE_NAME}.mobileprovision" "${TEMP}/Payload/${APP_NAME}.app/embedded.mobileprovision"

        #Change icon
        echo "Change icon"
        cp "./module/$file2${ASSETS_PATH}/icon_120.png" "${TEMP}/Payload/${APP_NAME}.app/AppIcon60x60@2x.png"
        cp "./module/$file2${ASSETS_PATH}/icon_180.png" "${TEMP}/Payload/${APP_NAME}.app/AppIcon60x60@3x.png"


        #Change Bundleversion
        if [[ ! -z ${APP_BUNDLE_VERSION} ]]; then
            /usr/libexec/PlistBuddy -c "Set CFBundleVersion ${APP_BUNDLE_VERSION}" ${TEMP}/Payload/${APP_NAME}.app/Info.plist
        fi

        #Change CFBundleShortVersionString
        if [[ ! -z ${APP_BUNDLE_SHORT_VERSION_STRING} ]]; then
            /usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString ${APP_BUNDLE_SHORT_VERSION_STRING}" ${TEMP}/Payload/${APP_NAME}.app/Info.plist
        fi

        #Change Bundleidentifier
        /usr/libexec/PlistBuddy -c "Set CFBundleIdentifier ${APP_ID}" ${TEMP}/Payload/${APP_NAME}.app/Info.plist

        #Create entitlements from template
        ENTITLEMENTS=$(<./templates/entitlements.template)
        ENTITLEMENTS=${ENTITLEMENTS//#APP_ID#/$APP_ID}
        ENTITLEMENTS=${ENTITLEMENTS//#APP_PREFIX#/$APP_PREFIX}
        echo ${ENTITLEMENTS} > ${TEMP}/entitlements.temp

        #Re-sign
        #这里注意命令参数的不同
        #/usr/bin/codesign -f -s "${CERTIFICATE_TYPE}: ${CERTIFICATE_NAME}" --identifier "${APP_ID}" --entitlements "${TEMP}/entitlements.temp" --resource-rules "${TEMP}/Payload/${APP_NAME}.app/ResourceRules.plist" "${TEMP}/Payload/${APP_NAME}.app"
        /usr/bin/codesign -f -s "${CERTIFICATE_TYPE}: ${CERTIFICATE_NAME}" --identifier "${APP_ID}" --entitlements "${TEMP}/entitlements.temp" "${TEMP}/Payload/${APP_NAME}.app"

         #Remove copyed mother package
        echo "Remove mother package"
        rm -rf ./module/$file2${ASSETS_PATH}packageExample.ipa

        #Re-package
        echo "Re-package"
        cd ${TEMP}
        zip -qr "${IPA_NAME}_resigned_${NOW}.ipa" Payload
        mv ${IPA_NAME}_resigned_${NOW}.ipa ../${BUILD_PATH}/${IPA_NAME}_${file2}_${NOW}.ipa



        #Remove temp
        cd ../
        rm -rf ${TEMP}

    fi
done
exit 0

代码中已经做了注释,做简单解释:

  1. 最外面对module文件夹for循环
  2. 读取conf配置文件(这些配置文件均是自己配置,实际也可以是plist文件,也比较方便)
  3. 把母包从外面拷贝进来
  4. 对拷贝过来的包进行解压,移除CodeResources等,替换描述文件,替换icon,修改BundleId及版本信息,修改授权文件(授权文件也是需要注意的点,inhouse和develop也有一点点区别,但整体没变)
  5. 然后就是codesign命令,代码注释也指出了 --resource-rules参数的问题,我原本找到的是带这个参数的,但是现在用不到。具体原因《代码签名探析》这里说是:“伴随 OS X 10.10 DP 5 和 10.9.5 版本的发布,苹果改变了代码签名的格式,也改变了有关资源的规则。如果你使用10.9.5或者更高版本的 codesign 工具,在 CodeResources 文件中会有4个不同区域,其中的 rules 和 files 是为老版本准备的,而 files2 和 rules2是为新的第二版的代码签名准备的。最主要的区别是在新版本中你无法再将某些资源文件排除在代码签名之外,在过去你是可以的,只要在被设置签名的程序包中添加一个名为 ResourceRules.plist 的文件,这个文件会规定哪些资源文件在检查代码签名是否完好时应该被忽略。但是在新版本的代码签名中,这种做法不再有效所有的代码文件和资源文件都必须设置签名,不再可以有例外。” 。简单的说,资源文件现在也必须重新签名了。
  6. 重新压缩包,并移动到build中。

整个流程走完后我们在build中得到了重新签名后的包,并且可以通过iTunes按照到设备上且能够正常打开,但是我们发现icon被换掉了,内部的bundleId、版本号信息等也被换了,于是乎,就这样轻轻松松的“换皮了”。我的手机上最后的截图如下:

这样做的优势

  1. 节省劳动
  2. 配置方便,例子中主要修改icon,其实还可以加一些配置文件来配置颜色啊字体啊文字啊等等
  3. 对于邪恶点的公司,申请很多app账号,然后用这个方法,快速换皮,app内部的内容接口根据bundleid等信息来配置,里面放放广告,对主版本进行导流量等。

自动部署

截止到目前为止,成功的导出了各种各样的包。离完全的自动化“只剩最后一公里“了,还可以继续的进行自动部署来完成这最后一公里。通过自动部署,我们可以直接将包发到AppStore、fir\蒲公英这样的第三方平台、以及自己的服务器上。这里重点推荐mattt大神的——SHENZHEN

SHENZHEN的安装和使用

通过gem安装

$ gem install shenzhen

具体的用法可以参见这里,毕竟在中国,主要提下FIR和蒲公英已经上传AppStore的命令:

FIR

$ ipa distribute:fir -u USER_TOKEN -a APP_ID  

蒲公英 (PGYER)

$ ipa distribute:pgyer -u USER_KEY -a APP_KEY

USER信息到各自注册账号查找

iTunes Connect Distribution

$ ipa distribute:itunesconnect -a me@email.com -p myitunesconnectpassword -i appleid --upload

我们仍然是可以通过读取配置信息,来写个脚本跑部署,这部分就不再举例了,如果你不小心看到这个系列我觉得你应该会了,或者我们也可以相互商讨(毕竟我的blog人读的少 o(╯□╰)o)。实际上,我的同事已经实现了。

论持续化集成

虽然iOS好像能使用Jenkins进行持续化集成(好像我也用了一下Jenkins,貌似不是很好用,可能是我没有坚持用吧),但是通过这个序列的文章,其实我们自己就实现了一套持续化集成了。刚开始用蒲公英那会儿我把ipa包传给他们,他们就能放到平台给其他人测试,我觉得好神奇啊,后来想想,无非就是重新签名。持续化集成其实我的同事也实现了,我们用了一台服务器,定时的拉取代码,跑脚本,然后上传到测试服务器供人下载使用。只是公司内部推广不好,毕竟不是大厂也好像不是那么工程师文化,所以巴拉巴拉。

结语

大半年前就想写这系列的文章了,当时研究了,但是由于懒和忙其他的就一直没有写,现在终于写完了。回顾一下,还是能了解不少东西的,加密,签名,打包,重签名,部署等等。这些可能是些冷知识吧,相比较什么runloop、runtime、gcd啊要冷的多的多。我觉得记录下来挺有意思的。

本系列参阅和参考的不完全统计有:

  1. SSL(https)中的对称加密和非对称加密
  2. RSA算法原理(一)
  3. Bypassing OpenSSL Certificate Pinning in iOS Apps
  4. Understanding provisioning profiles and certificates
  5. Code Signing explained
  6. Mach-O可执行文件
  7. iOS开发中的各种证书
  8. 代码签名探析
  9. 苹果证书和公钥私钥加密
  10. iOS8以后CodeSign失效问题
  11. iOS证书及ipa包重签名探究
  12. ipa包部署网页安装
  13. iOS Code Signing: Under The Hood
  14. How iOS developers use code signing to get their apps on iPhones
  15. iOS Code Signing 学习笔记
  16. 苹果开发者账号那些事儿(二)
  17. Inside Code Signing
  18. 公开密钥加密
  19. 数字签名

本文转载自:http://www.vienta.me/2016/02/25/iOS%E6%89%B9%E9%87%8F%E8%87%AA%E5%8A%A8%E6%89%93%E5%8C%85%E5%92%8...

共有 人打赏支持
hejunbinlan
粉丝 40
博文 534
码字总数 21018
作品 0
浦东
高级程序员
加载中

评论(4)

z
zb1503967447663
怎么修改重签名后的 appname?如果你的 appname 做了本地化呢?
阿陀罗
自动签名系统有吗
l
leonleonle
请问下,能不能稍微说下,这些脚本的具体用法:flushed:
l
leonleonle
五体投地地膜拜大神
【AR】开始使用Vuforia开发iOS(2)

原 设置iOS开发环境 安装Vuforia iOS SDK 如何安装Vuforia iOS示例 编译并运行Vuforia iOS示例 支持iOS金属 iOS 64位迁移 设置iOS开发环境 适用于iOS的Vuforia引擎目前支持运行iOS 9及更高版...

lichong951 ⋅ 06/11 ⋅ 0

iOS ZipperDown 漏洞来袭,我们该如何应对?

  昨天傍晚盘古实验室负责任的披露了针对 iOS 应用的 ZipperDown 漏洞,并提供了检索、查询受影响应用的平台: zipperdown.com。基于目前公开的信息,该漏洞的影响面比较大,15000 多个应用...

FreeBuf ⋅ 05/16 ⋅ 0

将成型的iOS工程嵌入到u3d工程中

一、合并iOS工程和u3d工程 1、一个U3d导出的Xcode工程Unity-iPhone,单独编译运行OK 2、一个iOS工程ARHere,单独编译运行OK 3、打开终端cd 到Unity-iPhone文件夹,vim Podfile,把ARHere的内...

朝雨晚风 ⋅ 2016/11/29 ⋅ 0

Dhar/YTTInjectedContentKit

YTTInjectedContentKit iOS壳版本场景下的批量修改类名、属性名、插入混淆代码、修改项目名称的shell脚本 具体的实现和使用方法请参考我的博客文章: iOS使用shell脚本注入混淆内容 iOS使用S...

Dhar ⋅ 05/04 ⋅ 0

iOS-Security 苹果安全白皮书都讲了些啥?

2017.03.27 原文地址 使用Google 按段落翻译(上传文档的不太准),通读一遍后去掉设备或网络的超专业术语,也算是筛选掉对开发者意义不大的信息吧! 苹果设计的 iOS 平台向来是以安全为核心...

si1ence ⋅ 2017/12/14 ⋅ 0

Unity与IOS交互,调用IOS系统相机和相册

前面两篇总结了一下unity与android的简单交互和调用安卓系统相机和相册,比较蛋疼的是,后来发现不同的测试机上会有不同的bug。。。下阶段要一个一个的解决一下 今天总结一下与IOS的交互。这...

qq_32587659 ⋅ 05/16 ⋅ 0

.a .framework打包注意事项

静态库中使用了C++混编 我们都知道在OC项目中使用了C++文件来混编的话,就会报如图所示的错误。其最快捷的解决方法就是将项目中的一个文件的.m后缀改成.mm。 如果在制作静态库时也使用了C++...

_故事的小黄瓜_ ⋅ 05/17 ⋅ 0

Unity调用IOS的StoreKit实现在游戏内部的对游戏进行星级评价和评论

一 Xcode端的OC代码 在Xcode里面新建一个空的工程(不会搞的百度一下),然后创建一个.h和.m文件,记住要把.m的后缀改成.mm(.mm文件和.m文件的区别就是:.mm文件除了可以包含Objective-C和C...

caohonghong123 ⋅ 04/19 ⋅ 0

React Native Mac 下打包Android APK

打包的时候遇到了 好多坑 这里记录下~ 主要步骤: 1.android keystore签名的生成 gradle mac下环境变量的配置 3.android studio中的gradle配置。 4.打包 签名的生成 执行完之后,输入本机的 ...

JsLin_ ⋅ 06/18 ⋅ 0

2018 一份"有点难"的iOS面试题(5年iOS开发)

序言: 之前一时兴致在本站上出过一份iOS的中级面试题,引起一些关注,不少同学表示对”隐藏关卡“感兴趣。升级版iOS面试题来了,目测难倒90%iOS程序员,目测一大波程序员撸着袖子在靠近。 ...

原来是泽镜啊 ⋅ 05/26 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

6. Shell 函数 和 定向输出

Shell 常用函数 简洁:目前没怎么在Shell 脚本中使用过函数,哈哈,不过,以后可能会用。就像java8的函数式编程,以后获取会用吧,行吧,那咱们简单的看一下具体的使用 Shell函数格式 linux ...

AHUSKY ⋅ 7分钟前 ⋅ 0

MySQL 内核深度优化

MYSQL数据库适用场景广泛,相较于Oracle、DB2性价比更高,Web网站、日志系统、数据仓库等场景都有MYSQL用武之地,但是也存在对于事务性支持不太好(MySQL 5.5版本开始默认引擎才是InnoDB事务...

OSC_cnhwTY ⋅ 14分钟前 ⋅ 0

单片机软件定时器

之前写了一个软件定时器,发现不够优化,和友好,现在重写了 soft_timer.h #ifndef _SOFT_TIMER_H_#define _SOFT_TIMER_H_#include "sys.h"typedef void (*timer_callback_function)(vo...

猎人嘻嘻哈哈的 ⋅ 16分钟前 ⋅ 0

好的资料搜说引擎

鸠摩搜书 简介:鸠摩搜书是一个电子书搜索引擎。它汇集了多个网盘和电子书平台的资源,真所谓大而全。而且它还支持筛选txt,pdf,mobi,epub、azw3格式文件。还显示来自不同网站的资源。对了,...

乔三爷 ⋅ 24分钟前 ⋅ 0

Debian下安装PostgreSQL的表分区插件pg_pathman

先安装基础的编译环境 apt-get install build-essential libssl1.0-dev libkrb5-dev 将pg的bin目录加入环境变量,主要是要使用 pg_config export PATH=$PATH:/usr/lib/postgresql/10/bin 进......

玛雅牛 ⋅ 25分钟前 ⋅ 0

inno安装

#define MyAppName "HoldChipEngin" #define MyAppVersion "1.0" #define MyAppPublisher "Hold Chip, Inc." #define MyAppURL "http://www.holdchip.com/" #define MyAppExeName "HoldChipE......

backtrackx ⋅ 54分钟前 ⋅ 0

Linux(CentOS)下配置php运行环境及nginx解析php

【part1:搭建php环境】 1.选在自己需要安装的安装包版本,wget命令下载到服务器响应目录 http://php.net/releases/ 2.解压安装包 tar zxf php-x.x.x 3.cd到解压目录执行如下操作 cd ../php-...

硅谷课堂 ⋅ 今天 ⋅ 0

Nginx服务架构初探(四):nginx服务器的rewrite功能

nginx服务器的rewrite功能 1.nginx后端服务器组的配置 1>upstream name {…} name是给服务器组限的组名 2>server address [parameters]; address为服务器地址 parame......

余温灬未存 ⋅ 今天 ⋅ 0

layer.prompt使文本框为空的情况下也能点击确定

最近一直在使用layui,但是用到弹出层layer.prompt时,如果文本框是空的话点击确定没有反应,不能向下执行。 但是我又需要空值,看看我原来的代码。 123456789 layer.prompt...

孟飞阳 ⋅ 今天 ⋅ 0

Linux普通文件压缩工具gzip、Bzip2、xz

第六章 文件压缩和打包 6.1 压缩打包介绍 Linux环境常见压缩文件类型: .zip,.gz,.bz2,.xz, .tar.gz,.tar.bz2,.tar.xz 压缩打包的目的 方便文件传输 节省磁盘空间 减少传输花费的时间 ...

弓正 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部