BuildDetails.swift 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. //
  2. // BuildDetails.swift
  3. // LoopFollow
  4. //
  5. // Created by Jonas Björkert on 2024-03-25.
  6. // Copyright © 2024 Jon Fawcett. All rights reserved.
  7. //
  8. import Foundation
  9. class BuildDetails {
  10. static var `default` = BuildDetails()
  11. let dict: [String: Any]
  12. init() {
  13. guard let url = Bundle.main.url(forResource: "BuildDetails", withExtension: "plist"),
  14. let data = try? Data(contentsOf: url),
  15. let parsed = try? PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any] else {
  16. dict = [:]
  17. return
  18. }
  19. dict = parsed
  20. }
  21. var buildDateString: String? {
  22. return dict["com-LoopFollow-build-date"] as? String
  23. }
  24. var branch: String? {
  25. return dict["com-LoopFollow-branch"] as? String
  26. }
  27. var branchAndSha: String {
  28. let branch = branch ?? "Unknown"
  29. let sha = dict["com-LoopFollow-commit-sha"] as? String ?? "Unknown"
  30. return "\(branch) \(sha)"
  31. }
  32. // Determine if the build is from TestFlight
  33. func isTestFlightBuild() -> Bool {
  34. #if targetEnvironment(simulator)
  35. return false
  36. #else
  37. if Bundle.main.url(forResource: "embedded", withExtension: "mobileprovision") != nil {
  38. return false
  39. }
  40. guard let receiptName = Bundle.main.appStoreReceiptURL?.lastPathComponent else {
  41. return false
  42. }
  43. return "sandboxReceipt".caseInsensitiveCompare(receiptName) == .orderedSame
  44. #endif
  45. }
  46. // Parse the build date string into a Date object
  47. func buildDate() -> Date? {
  48. guard let dateString = dict["com-LoopFollow-build-date"] as? String else {
  49. return nil
  50. }
  51. let formatter = ISO8601DateFormatter()
  52. return formatter.date(from: dateString)
  53. }
  54. // Calculate the expiration date based on the build type
  55. func calculateExpirationDate() -> Date {
  56. if isTestFlightBuild(), let buildDate = buildDate() {
  57. // For TestFlight, add 90 days to the build date
  58. return Calendar.current.date(byAdding: .day, value: 90, to: buildDate)!
  59. } else {
  60. // For Xcode builds, use the provisioning profile's expiration date
  61. if let provision = MobileProvision.read() {
  62. return provision.expirationDate
  63. } else {
  64. return .distantFuture
  65. }
  66. }
  67. }
  68. // Expiration header based on build type
  69. var expirationHeaderString: String {
  70. if isTestFlightBuild() {
  71. return "TestFlight Expires"
  72. } else {
  73. return "App Expires"
  74. }
  75. }
  76. }