xcode 8后,原来用企业证书 wildcard 打包,会因为没有 APNS 报错,所以只能指定 bundleIdentifier,但是指定之后,就不能和正常上线的 bundleIdentifier 一致了,每次打包就要重新设置一下 bundle identifier。解决方案 1、用两个 target,分开设置。2、makefile 打包的时候分别 设置 企业证书 和 上线证书。本文采用 第二种方案
一、配置参数:
version=$(shell /usr/libexec/PlistBuddy -c "print :CFBundleShortVersionString" ${infoPath})
tembundleDisplayName=$(shell /usr/libexec/PlistBuddy -c "print :CFBundleDisplayName" ${infoPath})
tembuildNumber=$(shell svn info |grep Revision)
buildNumberInfo=$(shell git log -a |wc -l | sed 's/^[ \t]*//g')
buildNumber=$(shell git log -1 --pretty=format:%h)_$(shell git log -a |wc -l | sed 's/^[ \t]*//g')
# 代码中的宏定义,定义 测试环境
serverEnvironment=BUILD_FOR_TEST
developmentTeam="NM9VP4YSNU"
productBundleIdentifier="com.***.***enterprise"
profileName=wildcard_can_push
profileID=aa64f6e9-4156-45b3-ae33-718ca2b24593
archivePath=build/DerivedData/neighborhood.xcarchive
bundleDisplayName="$(tembundleDisplayName)-e"
signKey=$(KEY_enterprise)
configWay=Adhoc
路径和文件名称 最好不要带空格,会把 shell 脚本 的参数 给 打乱。如果真有空格,就只能做转义了
# makefile 转义 infoPath 中的空格
infoPathFormat=$(subst \ ,\\ ,./neighborhood/Support Files/neighborhood-Info.plist)
二、修改 企业证书打包的 build 号,显示名称
因为用了不同的 bundle identifier,会有两个 app,为了到设备上区分出来,displayName 也设置不同的名称区分。
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $(buildNumberInfo)" "$(infoPathFormat)"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $(bundleDisplayName)" "$(bundleDisplayName)"
key
值可以把 info.plist 用文本文件打开查看。
三、打开钥匙串访问, 导入证书
security unlock-keychain "-p" 系统密码 "/Users/***/Library/Keychains/login.keychain" ;
我用的电脑 证书都已导入钥匙串,所以不用执行导入。
四、清理项目
xcodebuild -workspace ***.xcworkspace -scheme *** -configuration Adhoc clean
五、编译
因为 PackageApplication 已经弃用,改用 xcodebuild -exportArchive ,所以 编译 也改用 archive,xcodebuild archive
1、编译 pods
xcodebuild -workspace ***.xcworkspace -scheme Pods-*** -derivedDataPath build/DerivedData OBJROOT=$(PWD)/build SYMROOT=$(PWD)/build -configuration $(configWay)
2、编译 workspace
xcodebuild -workspace ***.xcworkspace -scheme *** -configuration $(configWay) -derivedDataPath build/DerivedData -archivePath "$(archivePath)" DEVELOPMENT_TEAM="$(developmentTeam)" PRODUCT_BUNDLE_IDENTIFIER="$(productBundleIdentifier)" CODE_SIGN_IDENTITY="$(signKey)" PROVISIONING_PROFILE="$(profileID)" PROVISIONING_PROFILE_SPECIFIER="$(profileName)" IPHONEOS_DEPLOYMENT_TARGET="7.0" archive
"***" 都替换成自己的。
因为 项目本身的设置都是 上线证书,这里要全部改成和 企业证书 用的配置 一模一样,所以 添加的参数比较多,少了一个编译就过不去。
参数和 正常在 xcode -> build setting 里面会有点不一样,可以把工程用文本编辑器打开,查找对应的名称:
图种的设置 应该都可以通过 xcodebuild 来设置。
参考 苹果官方文档 buildSettings
我们需要重新设置 证书和配置文件
需要设置的项目:
DEVELOPMENT_TEAM="$(developmentTeam)"
PRODUCT_BUNDLE_IDENTIFIER="$(productBundleIdentifier)"
CODE_SIGN_IDENTITY="$(signKey)"
PROVISIONING_PROFILE="$(profileID)"
PROVISIONING_PROFILE_SPECIFIER="$(profileName)"
IPHONEOS_DEPLOYMENT_TARGET="7.0"
profileID 可以通过 xcode-> account 里面查看。也可以通过脚本获取
获取 profile 的 ID
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage: getmobileuuid the-mobileprovision-file-path"
exit 1
fi
# mobileprovision_uuid=`grep UUID -A1 -a $1 | grep -o "[-A-Z0-9]\{36\}"`
mobileprovision_uuid=`/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< $(/usr/bin/security cms -D -i $1)`
echo "UUID is:"
echo ${mobileprovision_uuid}
添加 GCC_PREPROCESSOR_DEFINITIONS
环境变量
如果代码里面是用 宏定义来区分不同的网络 环境,比如 测试,预发,正式 环境,可以通过 传入 GCC_PREPROCESSOR_DEFINITIONS
来实现
例如代码中定义
//#define BUILD_FOR_DEVELOP
#define BUILD_FOR_TEST
//#define BUILD_FOR_PRERELEASE
//#define BUILD_FOR_RELEASE
if [ ${environment} == "test" ]; then
serverEnvironment=BUILD_FOR_TEST
elif [[ ${environment} == "prerelease" ]]; then
serverEnvironment=BUILD_FOR_PRERELEASE
elif [[ ${environment} == "release" ]]; then
serverEnvironment=BUILD_FOR_RELEASE
elif [[ ${environment} == "develop" ]]; then
serverEnvironment=BUILD_FOR_DEVELOP
else
echo "未知 环境,退出"
help_info
exit;
fi
那么 可以再 编译的时候,带上 GCC_PREPROCESSOR_DEFINITIONS
参数
GCC_PREPROCESSOR_DEFINITIONS_Adhoc=(${serverEnvironmentDefine},${configInfo},"\$(inherited)")
例如:
xcodebuild -workspace neighborhood.xcworkspace -scheme neighborhood -configuration ${configWay} -derivedDataPath build/DerivedData -archivePath "${archivePath}" DEVELOPMENT_TEAM="${developmentTeam}" PRODUCT_BUNDLE_IDENTIFIER="${productBundleIdentifier}" CODE_SIGN_IDENTITY="${signKey}" PROVISIONING_PROFILE="${profileID}" PROVISIONING_PROFILE_SPECIFIER="${profileName}" IPHONEOS_DEPLOYMENT_TARGET="7.0" archive GCC_PREPROCESSOR_DEFINITIONS=${GCC_PREPROCESSOR_DEFINITIONS_Adhoc}
但是 如果直接就写
GCC_PREPROCESSOR_DEFINITIONS='$(GCC_PREPROCESSOR_DEFINITIONS) $(serverEnvironment) $(configInfo)'
则不会生效,不知道为什么。
可以参考:https://stackoverflow.com/questions/1402641/xcode-how-to-set-debug-environment-with-multiple-xcconfig-files/7907294
六、 打包
改用 xcodebuild -exportArchive
xcodebuild -exportArchive -exportFormat IPA -archivePath "$(archivePath)" -exportPath $(out_path)/$(ddxq_ipaName) -exportProvisioningProfile "$(profileName)"
这里 需要注意,最好带上 -exportProvisioningProfile
,不然虽然能打包 ipa,但是 安装不到手机上。这里 设置为 配置文件名称就好,不是profile 的 UUID。
可以参考 这里,对各字段对应哪里 描述的比较清楚。
如果 设置不对,则会报错:"no provisioning profile matches:****"
报错
1、xcodebuild error: no provisioning profile matches
xcodebuild 后面跟的 配置文件,证书,team,要全部匹配。
2、archive 报:“ archive at path '/build/.xcarchive' is malformed”
这是因为刚开始 设置了
-derivedDataPath build/DerivedData
OBJROOT=$(PWD)/build
SYMROOT=$(PWD)/build
最后发现 只需要 -derivedDataPath
就够了。
3、 安装时报 “A signed resource has been added modified or deleted”
是因为 最后 export archive 的时候没有带上 -exportProvisioningProfile
。
参考:这里
完整脚本
传送门
参考资料:
- https://blog.reohou.com/how-to-export-ipa-from-archive-using-xcodebuild/
- 苹果官方
xcodebuild
文档 - http://liumh.com/2015/11/25/ios-auto-archive-ipa/
- http://www.cocoachina.com/ios/20151104/14050.html