Skip to content
13 changes: 13 additions & 0 deletions Sources/Gravatar/BundleInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@ package enum BundleInfo {
getInfoValue(forKey: "CFBundleShortVersionString") as? String
}

/// The `CFBundleName`.
///
/// This string may be localized.
package static var appName: String? {
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String
}

/// The `CFBundleExecutable` name.
package static var executableName: String? {
Bundle.main.object(forInfoDictionaryKey: "CFBundleExecutable") as? String
}

package static var appIdentifier: String? {
guard let bundleID = Bundle.main.bundleIdentifier else { return nil }
return String(bundleID.hashed().prefix(10))
}

private static func getInfoValue(forKey key: String) -> Any? {
// Access the SDKInfo.plist using Bundle.module
guard let url = Bundle.module.url(forResource: "SDKInfo", withExtension: "plist"),
Expand Down
26 changes: 24 additions & 2 deletions Sources/Gravatar/Network/Services/URLSessionHTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@ enum HTTPClientError: Error {
case URLSessionError(Error)
}

private enum Constants {
static let sdkName = "Gravatar-SDK"
}

struct URLSessionHTTPClient: HTTPClient {
private let urlSession: URLSessionProtocol

init(urlSession: URLSessionProtocol? = nil) {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = [
"Accept": "application/json",
"X-Platform": "ios",
"X-Platform": osName().lowercased(),
"X-SDK-Version": BundleInfo.sdkVersion ?? "",
"X-Source": BundleInfo.appName ?? "",
"X-Source": BundleInfo.executableName ?? "",
"User-Agent": Self.userAgent,
]
self.urlSession = urlSession ?? URLSession(configuration: configuration)
}
Expand Down Expand Up @@ -51,6 +56,23 @@ extension URLRequest {
}
}

extension URLSessionHTTPClient {
private static var userAgent: String {
"\(Constants.sdkName)/\(BundleInfo.sdkVersion) (\(osName()) \(ProcessInfo.processInfo.osVersionDottedString); AppID \(BundleInfo.appIdentifier ?? "Unknown"))"
}
}

private func osName() -> String {
let osName: String
#if os(iOS)
osName = "iOS"
#else
osName = "Unknown OS"
assertionFailure("Update '\(#function)' to include the current OS name (iOS, macOS, tvOS, watchOS) when adding support for it.")
#endif
return osName
}

private func validatedHTTPResponse(_ response: URLResponse, data: Data) throws -> HTTPURLResponse {
guard let httpResponse = response as? HTTPURLResponse else {
throw HTTPClientError.invalidURLResponseError(response)
Expand Down
7 changes: 7 additions & 0 deletions Sources/Gravatar/ProcessInfo+Additions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation

extension ProcessInfo {
var osVersionDottedString: String {
"\(operatingSystemVersion.majorVersion).\(operatingSystemVersion.minorVersion).\(operatingSystemVersion.patchVersion)"
}
}