由于公司项目需求然后想要一个项目打包多个包,然后app名字、bundleId、服务器连接URL、appIocn、app项目内容渠道参数不一样,针对网上看了一些教程和方式,现在总结一下。 如果想要知道单个项目脚本打包请查看IOS脚本单独打包
一、bash脚本 bash 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。bash 既是一种命令语言,又是一种程序设计语言。bash脚本基础学习
项目目录结构
结构说明:
MutaPackageScript.sh : 为脚本文件 (批量时部分配置修改)
Plist:为打包4种打包模式 AdHoc、AppStore、Development、Enterprise (不需要动)
1 2 3 4 5 6 7 8 9 10 11 12 <?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 > method</key > <string > development</string > //这儿development、enterprise、ad-hoc、app-store四种 <key > signingStyle</key > <string > automatic</string > <key > compileBitcode</key > <false /> </dict > </plist >
AppIcon: 为要打包的替换的AppIcon图系列,这儿首先要用工具生成好所有图,名字必须是AppIcon~系列的,原因是同一个包脚本会替换覆盖操作。我是使用的一个Asset Catalog Creator 你自己使用其他的也行,能生成就行。(需要使用工具生成)
目录子目录文件夹就是当打包多个的时候AppIcon文件目录,名字对应的脚本文件的里的配置文件appIconArr参数的名字,修改app文件配置参数,所以如果新增APP时请修改新增此脚本参数,不然会找不到APPIcon文件图片替换目录。
1 2 3 4 appIconArr=( "yqb_AppIcon" "lebzs_AppIcon" )
这儿启动图和引导图都可以放在这个里面,然后会同一替换,主要图片名字记得保持一致,例如在项目中启动图叫
launch_s.png,重新打包的时候也请命名为launch_s.png放在AppIcon文件夹包里。
二、开始打包操作
1 2 cd /Users/mac/Desktop/您的项目名称/MutaPackageScriptsh MutaPackageScript.sh
上面要cd到当前项目文件夹下的MutaPackageScript脚本目录,原因是为了当其他项目在不同的目录路径下时,获取到项目层级会不一致,不同的电脑上可能不是同一个,所以cd项目时需要先项目目录文件下MutaPackageScript目录下。
所有脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 #!/bin/bash # Script.sh # Package # Created by wws on 2023/02/25. # Copyright © 2023 年 wws. All rights reserved. # 1.Configuration Info # 是否编译工作空间 (例:若是用Cocopods管理的.xcworkspace项目,赋值true;用Xcode默认创建的.xcodeproj,赋值false) is_workspace="true" # 指定要打包编译的方式 : Release,Debug... build_configuration="Release" # 返回上一级目录,进入项目工程目录 cd .. # 获取项目名称 projectName=`find . -name *.xcodeproj | awk -F "[/.]" '{print $(NF-1)}'` # Scheme Name schemeName=${projectName} #cd ~/Desktop/${schemeName} # 图标路径 iconPath="./MutaPackageScript/AppIcon" # 打包所有生成路径 ipaPath=~/Desktop/ IPAS # 临时生成APP路径 buildDir="${ipaPath}/build/${schemeName}.xcarchive" plistPath="./MutaPackageScript/Plist" # 导出ipa所需要的plist文件路径 (默认为AdHocExportOptionsPlist.plist) exportOptionsPlistPath="${plistPath}/AdHocExportOptionsPlist.plist" #app名字 displayNameArr=( "app1的名字" "app2的名字" ) #app的bundleId bundleIdentifierArr=( "com.qyf.qyf" "com.qyf.ysf" ) #获取URL链接的主机地址编号 hostNumberArr=( "A022" "A021" ) #修改app文件地址 appIconArr=( "yqb_AppIcon" "lebzs_AppIcon" ) #打包渠道号 channelCodeArr=( "112" "115" ) #版本号 versionArr=( "1.0.3" "1.0.4" ) #服务器默认连接的地址 serverArr=( "https://www.xxx.com/app1/" "https://www.xxx.com/app2/" ) # 开始时间 beginTime=`date +%s` # 清除缓存 rm -rf mkdir ${ipaPath} # 创建打包目录 mkdir ${ipaPath} # 蒲公英分发参数 不分发可忽略 默认不分发 下面的两个KEY是默认测试的网址对应KEY 换成你自己的 isUploadPgyer=0 USERKEY="xxx" APIKEY="xxx" # fir分发参数 不分发可忽略 默认分发 Token换成你自己的 isUploadFir=1 FirApiToken="931b41960fd413455496b9465ec910adb97" # AdHoc,AppStore,Enterprise,Development四种打包方式 echo "\033[36;1m请选择打包方式(输入序号,按回车即可) \033[0m" echo "\033[33;1m1. AdHoc \033[0m" echo "\033[33;1m2. AppStore \033[0m" echo "\033[33;1m3. Enterprise \033[0m" echo "\033[33;1m4. Development \033[0m" #读取用户输入并存到变量里 read parameter sleep 0.5 method="$parameter" # 判读用户是否有输入 if [ -n "$method" ]then if [ "$method" = "1" ] ; then exportOptionsPlistPath="${plistPath}/AdHocExportOptionsPlist.plist" elif [ "$method" = "2" ] ; then exportOptionsPlistPath="${plistPath}/AppStoreExportOptionsPlist.plist" elif [ "$method" = "3" ] ; then exportOptionsPlistPath="${plistPath}/EnterpriseExportOptionsPlist.plist" elif [ "$method" = "4" ] ; then exportOptionsPlistPath="${plistPath}/DevelopmentExportOptionsPlist.plist" else echo "输入的参数无效!!!" exit 1 fi fi echo "\033[32m************************* 开始构建项目 ************************* \033[0m" path="${ipaPath}/build" # 删除临时旧的xcarchive文件和打包项目 rm -rf mkdir ${path} mkdir ${path} # 指定输出文件目录不存在则创建 if [ -d "$path" ] ; thenecho $path else mkdir -pv $path fi # Build 生成 APPs # 判断编译的项目类型是workspace还是project if $is_workspace ; then# 编译前清理工程 xcodebuild clean -workspace ${projectName}.xcworkspace \ -scheme ${schemeName} \ -configuration ${build_configuration} xcodebuild archive -workspace ${projectName}.xcworkspace \ -scheme ${schemeName} \ -configuration ${build_configuration} \ -archivePath ${buildDir} else # 编译前清理工程 xcodebuild clean -project ${projectName}.xcodeproj \ -scheme ${schemeName} \ -configuration ${build_configuration} xcodebuild archive -project ${projectName}.xcodeproj \ -scheme ${schemeName} \ -configuration ${build_configuration} \ -archivePath ${buildDir} fi # 检查是否构建成功 # xcarchive 实际是一个文件夹不是一个文件所以使用 -d 判断 if [ -d "$buildDir" ] ; thenecho "\033[32;1m项目构建成功 \033[0m" else echo "\033[31;1m项目构建失败 \033[0m" exit 1 fi appPackNum=${#displayNameArr[*]} # ----全部打包---- for (( i=0 ; i<appPackNum; i++ )); do # App DisPlay Name 打包名字 displayName=${displayNameArr[${i}]} # App BundleIdentifier 打包标识ID bundleIdentifier=${bundleIdentifierArr[${i}]} # App Icon File Name 打包AppIocn文件路径 appIcon=${appIconArr[${i}]} # App channelCode 打包渠道 channelCode=${channelCodeArr[${i}]} # App hostNumber 请求的主机地址编号 hostNumber=${hostNumberArr[${i}]} # App version 版本号 version=${versionArr[${i}]} # App hostUrl 服务器地址 hostUrl=${serverArr[${i}]} # 创建不同 app ipa 目录 rm -rf $ipaPath/${displayName} mkdir $ipaPath/${displayName} echo "33[31m appName:$displayName appIconName:$appIcon appChannelName:$channelCode bundleID:$bundleIdentifier n 33[0m" # 将对应的 icon 复制到需要修改的 app 的目录下 # .xcarchive 文件下对应的Applications文件路径 Applications_Path=${buildDir}/Products/Applications cp -Rf `${iconPath} /${appIcon} /*` `$Applications_Path/*.app` if [[ $? = 0 ]]; then echo "33[31m 修改 icon 成功33[0m" else echo "33[31m 修改 icon 失败33[0m" fi # 修改 Plist # plist路径 infoPlist_File_Path=`$Applications_Path/*.app/info.plist` /usr/libexec/PlistBuddy -c "Set :CFBundleName $displayName" $infoPlist_File_Path /usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $displayName" $infoPlist_File_Path /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $bundleIdentifier" $infoPlist_File_Path /usr/libexec/PlistBuddy -c "Set :ChannelCode $channelCode" $infoPlist_File_Path /usr/libexec/PlistBuddy -c "Set :HostNumber $hostNumber" $infoPlist_File_Path /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $version" $infoPlist_File_Path /usr/libexec/PlistBuddy -c "Set :HostUrl $hostUrl" $infoPlist_File_Path if [[ $? = 0 ]]; then echo "33[31m 修改 Plist 成功33[0m" else echo "33[31m 修改 Plist 失败33[0m" fi # 重签名 #codesign -f -s "iPhone Distribution: Beijing Waming Environmental Technology Co., Ltd" --entitlements $exportOptionsPlistPath ${ipaPath}/Payload/${schemeName}.app #if [[ $? = 0 ]]; then #echo " 签名成功n " #else #echo " 签名失败n " #fi # 生成 ipa xcodebuild -exportArchive -archivePath ${ipaPath}/build/${schemeName}.xcarchive -exportOptionsPlist ${exportOptionsPlistPath} -exportPath ${ipaPath}/${displayName} -allowProvisioningUpdates ${YES} -allowProvisioningDeviceRegistration ${YES} if [[ $? = 0 ]]; then echo "33[31m n 生成 IPA 成功 nnnnn33[0m" else echo "33[31m n 生成 IPA 失败 nnnnn33[0m" fi rm -rf ${ipaPath}/${displayName}/${projectName}.xcarchive # 上传fir if [[ $isUploadFir = 1 ]]; then echo "正在上传fir..." fir p "${ipaPath}/${displayName}/${displayName}.ipa" -T ${FirApiToken} fi # 移动 #mv ${ipaPath}/$displayName/$displayName.ipa ${allIPAPackPath}/$appName # 上传蒲公英分发平台 if [[ $ISUPLOAD = 1 ]]; then echo "正在上传蒲公英..." curl -F "file=@$ipaPath/$displayName/$displayName.ipa" -F "uKey=$USERKEY" -F "_api_key=$APIKEY" http: fi done # 结束时间 endTime=`date +%s` echo -e "打包时间$[ endTime - beginTime ]秒"
判读用户是否有输入 1、AdHoc 2、AppStore 3、Enterprise 4、Development
如果打包出现证书匹配问题,如果选择的auto 脚本里需要配置 ,上面脚本已经配置。
-allowProvisioningUpdates ${YES}
-allowProvisioningDeviceRegistration ${YES}
如果打包报其他错误,请先在Xcode项目上保证能archive,先解决掉代码上的错误才能保证脚本打包。
等待生成ipa其中这儿生成替换的参数在APP中会读取,这儿也可以根据自己项目需求自定参数到info.plist下,然后在项目代码里实际的功能需求来操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #app名字 displayNameArr=( "渝钱宝管家" "开益宝助手" ) #app的bundleId bundleIdentifierArr=( "com.qyf.qyf" "com.qyf.qyf" ) #获取URL链接的主机地址编号 hostNumberArr=( "A022" "A021" ) #修改app文件地址 appIconArr=( "yqb_AppIcon" "lebzs_AppIcon" ) #打包渠道号 channelCodeArr=( "112" "115" )
这儿举个简单的例子例如hostNumberArr参数,在实际项目中是为了请求URL服务器地址的,然后在项目里获取到info.plist文件读取出来过后,然后在去请求服务器请求地址代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 //获取开关配置和切换IP地址数据 +(void)updateHostUrlSysCnfBlock:(void(^)(void))block{ AFHTTPSessionManager *manger =[AFHTTPSessionManager manager]; [manger.requestSerializer willChangeValueForKey:@"timeoutInterval"]; manger.requestSerializer.timeoutInterval = 20.f; [manger.requestSerializer didChangeValueForKey:@"timeoutInterval"]; NSString *hostNumber = [NSBundle mainBundle].infoDictionary[@"HostNumber"]; NSString *getURL = [NSString stringWithFormat:@"http://sys.xxxx.cn:10271/geturl?v=%@",hostNumber]; [manger GET:getURL parameters:nil headers:nil progress:^(NSProgress *downloadProgress) { } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSDictionary *info = (NSDictionary *)responseObject; if (info) { DataInstance.hideFlag = ((NSString *)info[@"hideFlag"]).integerValue; NSString *hostUrl = info[@"url"]; if(![AppUtils isEmptyStr:hostUrl]){ hostUrl =[NSString stringWithFormat:@"%@/",info[@"url"]]; if (![DataInstance.hostUrl isEqualToString:hostUrl]) { #ifdef DEBUG #else DataInstance.hostUrl = hostUrl; [UserMgn cleanUser]; #endif } } } //进入控制器 if (block) {block();} } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"%@",error.localizedDescription); if (block) {block();} }]; }
三、生成IPAS产品系列包
如果没有安装fir插件,请先安装
1 sudo gem install fir-cli –no-ri –no-rdoc
执行成功会生成对应的项目文件目录
1 2 echo "fir平台..." fir p "${ipaPath}/${displayName}/${displayName}.ipa" -T 931 b41960f7496b946ei2s13c910pdb97
上面-T后面的token需要替换成你自己,上面只是例子随便的值,如果想要知道如果获取fir的token登陆fir官网看以下图
1 2 echo "正在上传蒲公英..." curl -F "file=@$ipaPath/$displayName/$displayName.ipa" -F "uKey=$USERKEY" -F "_api_key=$APIKEY" http:
方法不累述 USERKEY和APIKEY,上面默认的脚本不上传fir和pgyer,你可以根据自己需求,打开注释,和修改是否需要上传蒲公英的状态开关。
如果上传fri,对应的二维码就是生成在fir平台的安装包