Xcode 10构建阶段Shell脚本

时间:2018-09-26 18:46:53

标签: xcode10

在我们的项目中,我们从git标记等获取我们的发行版本,然后使用如下外壳脚本将其写入到构建文件夹的Info.plist:

GIT_RELEASE_VERSION=$(some git command) defaults write "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.*}" "CFBundleShortVersionString" "${GIT_RELEASE_VERSION#*v}"

这对于所有过去的Xcode版本都运行良好,但是在Xcode 10的New Build System中,这实际上无法更新info.list文件中的CFBundleShortVersionString。不过,该值已使用Xcode 10的旧版生成系统正确更新。

我向脚本添加了一些回显,并比较了New和Legacy系统上的构建日志,但看不到任何区别:

echo "git release version:" ${GIT_RELEASE_VERSION} echo "info path:" ${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.*} echo "grv:" "${GIT_RELEASE_VERSION#*v}"

不确定是否有人在新构建系统中遇到类似问题?

4 个答案:

答案 0 :(得分:2)

问题似乎在于,有时您的import UIKit import MapKit class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var resultWeather: UIImageView! @IBOutlet weak var arrairport: UITextField! @IBOutlet weak var depairport: UITextField! @IBOutlet weak var resultAirport: UILabel! @IBOutlet weak var fontAirports: UIImageView! @IBOutlet weak var resultTemp: UILabel! @IBOutlet weak var resultTempfar: UILabel! @IBOutlet weak var resultHum: UILabel! @IBOutlet weak var resultCeiling: UILabel! @IBOutlet weak var resultClouds: UILabel! @IBOutlet weak var resultWind: UILabel! @IBOutlet weak var resultPressure: UILabel! @IBOutlet weak var resultMetar: UILabel! @IBOutlet weak var resultTaf: UILabel! @IBOutlet weak var arrMap: MKMapView! @IBOutlet weak var depMap: MKMapView! @IBAction func getWeather(_ sender: UIButton) { sender.pulsate() if let url = URL(string: "http://fr.allmetsat.com/metar-taf/france.php?icao=" + depairport.text!.replacingOccurrences(of: " ", with: "-")) { let request = NSMutableURLRequest(url: url) let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in var message = "" if error != nil { print(error!) } else { if let unwrappedData = data { let dataString = NSString(data: unwrappedData, encoding: String.Encoding.utf8.rawValue); var stringSeparator = "METAR:</b> " if let contentArray = dataString?.components(separatedBy: stringSeparator) { if contentArray.count > 1 { stringSeparator = "</p></div><div class=\"c1\"" let newContentArray = contentArray[1].components(separatedBy: stringSeparator); if newContentArray.count > 1 { message = newContentArray[0] print(message) if (dataString?.contains("CAVOK"))!{ DispatchQueue.main.async { self.resultWeather.image = UIImage(named: "sun.png") }} else if (dataString?.contains("SKC"))!{ DispatchQueue.main.async { self.resultWeather.image = UIImage(named: "sun.png")} } else if (dataString?.contains("SCT"))!{ DispatchQueue.main.async { self.resultWeather.image = UIImage(named: "scattered.png")} } else if (dataString?.contains("OVC"))!{ DispatchQueue.main.async { self.resultWeather.image = UIImage(named: "overcast.png")} } else if (dataString?.contains("BKN"))!{ DispatchQueue.main.async { self.resultWeather.image = UIImage(named: "broken.png")} } else if (dataString?.contains("FEW"))!{ DispatchQueue.main.async { self.resultWeather.image = UIImage(named: "few.png")} } else if (dataString?.contains("NSC"))!{ DispatchQueue.main.async { self.resultWeather.image = UIImage(named: "sun.png")} } else if (dataString?.contains("RAIN"))!{ DispatchQueue.main.async { self.resultWeather.image = UIImage(named: "rain.png")} }}}}}} } task.resume(); if let url = URL(string: "http://fr.allmetsat.com/metar-taf/france.php?icao=" + self.depairport.text!.replacingOccurrences(of: " ", with: "-")) { let requesta = NSMutableURLRequest(url: url) let taska = URLSession.shared.dataTask(with: requesta as URLRequest) { data, response, error in var messagea = "" if error != nil { print(error!) } else { if let unwrappedData = data { let dataStringa = NSString(data: unwrappedData, encoding: String.Encoding.utf8.rawValue); var stringSeparatora = "<div class=\"c1b\"" if let contentArray = dataStringa?.components(separatedBy: stringSeparatora) { if contentArray.count > 1 { stringSeparatora = "</h1><p>" let newContentArray = contentArray[1].components(separatedBy: stringSeparatora); if newContentArray.count > 1 { messagea = newContentArray[0] print(messagea) }}}}; } if messagea == "" { messagea = "No data..." } DispatchQueue.main.sync(execute: { self.resultAirport.text = self.depairport.text! })}; taska.resume() } else { self.resultAirport.text = "0" }; //latitude variable (depAirportLat) if let urlcoord = URL(string:"https://flyawaysimulation.com/airports/" + self.depairport.text!.replacingOccurrences(of: " ", with: "-")) { let requestad = NSMutableURLRequest(url: urlcoord) let taskad = URLSession.shared.dataTask(with: requestad as URLRequest) { data, response, error in var depAirportLat = "" if error != nil { print(error!) } else { if let unwrappedData = data { let dataStringad = NSString(data: unwrappedData, encoding: String.Encoding.utf8.rawValue); var stringSeparatorad = "<dt>Latitude</dt>" if let contentArray = dataStringad?.components(separatedBy: stringSeparatorad) { if contentArray.count > 1 { stringSeparatorad = "</dd>" let newContentArray = contentArray[1].components(separatedBy: stringSeparatorad); if newContentArray.count > 1 { depAirportLat = newContentArray[0] print(depAirportLat) }}}}}}; taskad.resume() } } override func viewDidLoad() { super.viewDidLoad() //Do any additional setup after loading the view, typically from a nib. class gloVarDep { var depAirportLatReal = depAirportLat.dropFirst(5) var depAirportLatRealCoord = String(depAirportLatReal) var depAirportLatRealCoordFloat = (depAirportLatRealCoord as NSString).floatValue 将在Xcode创建Run Script Phase之前执行。如果您想确保脚本阶段在特定步骤之后运行,则需要使用输入来标记依赖项。

例如,添加:

Info.plist

作为脚本阶段的输入,应强制执行您要寻找的顺序:Xcode将创建$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH),此后的某个时间,您的脚本将执行并修改Info.plist

答案 1 :(得分:0)

这里是同样的问题...一种解决方法是先清理然后执行完整构建。

Xcode 10中的新构建系统在完全构建和增量构建中以不同的方式运行Process Info.plist步骤:

  • 全面构建:在处理资产之后,在链接情节提要之前(链接 步骤)
  • 增量:在嵌入框架之后,在签名之前。

实际的问题是脚本作为构建步骤运行并更新处理后的Info.plist文件,该脚本需要始终在文件处理之后但在签名之前运行。

答案 2 :(得分:0)

类似于以上答案(尚无法评论),但略有变化。

脚本输入文件:

$(PROJECT_DIR)/$(INFOPLIST_FILE)      
$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)

输出文件:

$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)

我用脚本来创建要点,该脚本用于设置捆绑软件的版本和一些额外的信息,例如标签,日期,分支。

https://gist.github.com/JoeMatt/aedd459c54a383373231719e508a2a36

答案 3 :(得分:0)

(Xcode 11.2)

  • 在新构建系统中,所有自定义构建步骤将在新构建系统的Process .../Info.plist步骤之前 运行

enter image description here

  • 要在Xcode完成构建后运行Shell脚本,可以将其作为构建后操作添加到方案中:

Product > Scheme > Edit Scheme... > Build > Post-actions

I stole this image from https://stackoverflow.com/a/54232034/969305

  • 如果要引用任何构建系统环境变量(例如BUILT_PRODUCTS_DIRINFOPLIST_PATH),请确保更改了从以下位置提供构建设置

  • 添加您的Shell脚本,但请记住,如果您在应用程序捆绑包中编辑任何文件(即Info.plist),则需要重新签名该应用程序。将此添加到您的帖子构建步骤中:

export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
/usr/bin/codesign --force --sign - --entitlements "${TARGET_TEMP_DIR}/${FULL_PRODUCT_NAME}.xcent" --timestamp=none "${CODESIGNING_FOLDER_PATH}"