Bundle+Extensions.swift 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import Foundation
  2. extension Bundle {
  3. var releaseVersionNumber: String? {
  4. infoDictionary?["CFBundleShortVersionString"] as? String
  5. }
  6. var buildVersionNumber: String? {
  7. infoDictionary?["CFBundleVersion"] as? String
  8. }
  9. var profileExpirationDateString: String? {
  10. guard
  11. let profilePath = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision"),
  12. let profileData = try? Data(contentsOf: URL(fileURLWithPath: profilePath)),
  13. // Note: We use `NSString` instead of `String`, because it makes it easier working with regex, ranges, substring etc.
  14. let profileNSString = NSString(data: profileData, encoding: String.Encoding.ascii.rawValue)
  15. else {
  16. print(
  17. "WARNING: Could not find or read `embedded.mobileprovision`. If running on Simulator, there are no provisioning profiles."
  18. )
  19. return nil
  20. }
  21. let regexPattern = "<key>ExpirationDate</key>[\\W]*?<date>(.*?)</date>"
  22. guard let regex = try? NSRegularExpression(pattern: regexPattern, options: []),
  23. let match = regex.firstMatch(
  24. in: profileNSString as String,
  25. options: [],
  26. range: NSRange(location: 0, length: profileNSString.length)
  27. ),
  28. let range = Range(match.range(at: 1), in: profileNSString as String)
  29. else {
  30. print("Warning: Could not create regex or find match.")
  31. return nil
  32. }
  33. return String(profileNSString.substring(with: NSRange(range, in: profileNSString as String)))
  34. }
  35. var profileExpirationDate: Date? {
  36. guard let dateString = profileExpirationDateString else { return nil }
  37. let dateFormatter = DateFormatter()
  38. dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
  39. dateFormatter.locale = Locale(identifier: "en_US_POSIX")
  40. dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
  41. return dateFormatter.date(from: dateString)
  42. }
  43. var profileExpiration: String {
  44. guard
  45. let profilePath = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision"),
  46. let profileData = try? Data(contentsOf: URL(fileURLWithPath: profilePath)),
  47. // Note: We use `NSString` instead of `String`, because it makes it easier working with regex, ranges, substring etc.
  48. let profileNSString = NSString(data: profileData, encoding: String.Encoding.ascii.rawValue)
  49. else {
  50. print(
  51. "WARNING: Could not find or read `embedded.mobileprovision`. If running on Simulator, there are no provisioning profiles."
  52. )
  53. return "N/A"
  54. }
  55. // NOTE: We have the `[\\W]*?` check to make sure that variations in number of tabs or new lines in the future does not influence the result.
  56. guard let regex = try? NSRegularExpression(pattern: "<key>ExpirationDate</key>[\\W]*?<date>(.*?)</date>", options: [])
  57. else {
  58. print("Warning: Could not create regex.")
  59. return "N/A"
  60. }
  61. let regExMatches = regex.matches(
  62. in: profileNSString as String,
  63. options: [],
  64. range: NSRange(location: 0, length: profileNSString.length)
  65. )
  66. // NOTE: range `0` corresponds to the full regex match, so to get the first capture group, we use range `1`
  67. guard let rangeOfCapturedGroupForDate = regExMatches.first?.range(at: 1) else {
  68. print("Warning: Could not find regex match or capture group.")
  69. return "N/A"
  70. }
  71. let dateWithTimeAsString = profileNSString.substring(with: rangeOfCapturedGroupForDate)
  72. guard let dateAsStringIndex = dateWithTimeAsString.firstIndex(of: "T") else {
  73. return ""
  74. }
  75. return String(dateWithTimeAsString[..<dateAsStringIndex])
  76. }
  77. }