Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let package = Package(
.library(
name: "Analytics",
targets: ["Analytics"]
),
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-http-types", from: "1.3.0"),
Expand All @@ -35,9 +35,6 @@ let package = Package(
dependencies: [
.target(name: "Analytics"),
.product(name: "HTTPTypesFoundation", package: "swift-http-types"),
],
resources: [
.process("Resources")
]
),
]
Expand Down
92 changes: 91 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,93 @@
# firebaseanalytics-swift

Firebase Analytics client for Swift.
> [!IMPORTANT]
> This project is under development

Firebase Analytics Client for Swift.

```swift
let clientInformation: ClientInformation = .init(
os: "ios",
osVersion: "18.3",
deviceModel: "iPhone17,3",
locale: "ja-jp",
localeId: 540,
installMethod: "manual_install",
bundleId: "com.apple.SampleApp",
appVersion: "1.0",
googleAppId: "1:21332412389:ios:11681asd2a3cd5d8"
)

let session: Session = .init(
firstInteraction: false,
firstOpenTime: 1_737_550_800_666,
nonPersonalizedAds: false,
sessionId: 1_737_555_666,
sessionNumber: 2,
lifetimeEngagement: 1_175_666,
sessionEngagement: 10055,
userId: "user-id"
)

let payload = Payload(
value: 1,
events: [
EventPayload(
eventName: "login",
parameters: [
.method: "Google",
.platform: "app",
],
previousTimestampMillis: UInt(Date.now.timeIntervalSince1970 * 100),
timestampMillis: UInt(Date.now.timeIntervalSince1970 * 100)
),
EventPayload(
eventName: "_e",
parameters: [
"_et": .uint(891),
.platform: "auto"
],
previousTimestampMillis: UInt(Date.now.timeIntervalSince1970 * 100),
timestampMillis: UInt(Date.now.timeIntervalSince1970 * 100)
),
],
sessionInformations: session.parameters,
value4: UInt(Date.now.timeIntervalSince1970 * 100), // upload_timestamp_millis
value5: UInt(Date.now.timeIntervalSince1970 * 100), // start_timestamp_millis
value6: UInt(Date.now.timeIntervalSince1970 * 100), // end_timestamp_millis
value7: UInt(Date.now.timeIntervalSince1970 * 100), // previous_bundle_end_timestamp_millis
os: clientInformation.os,
osVersion: clientInformation.osVersion,
deviceModel: clientInformation.deviceModel,
value11: clientInformation.locale,
value12: clientInformation.localeId,
installMethod: clientInformation.installMethod,
bundleId: clientInformation.bundleId,
appVersion: clientInformation.appVersion,
value17: 110700, // gmp_version
value18: 110700, // uploading_gmp_version
value21: "BC75E87831231231B7A179248F24080C", // fix // app_instance_id
value23: 25, // count up // bundle_sequential_index
googleAppId: clientInformation.googleAppId,
value26: UInt(Date.now.timeIntervalSince1970 * 100), // free // previous_bundle_start_timestamp_millis
value27: "CAIIJF38-E407-4954-BC16-F693A22F9FA9", // fix // resettable_device_id
value30: "d4Xw8qsfsadBoMYlsYHnot", // fix // firebase_instance_id
value31: 1, // app_version_major
value35: 1_727_127_969_769_945, // fix // config_version
value45: 42_820_019, // fix
value52: "G1--", // fix // consent_signals
value64: "google_signals", // fix
value71: "19911", // fix // consent_diagnostics
value72: 0, // fix
value77: 13 // count up
)

let analytics = Analytics(
httpClient: .urlSession(.shared),
userAgent: "SampleApp/1 CFNetwork/3826.400.120 Darwin/24.3.0",
clientInformation: clientInformation,
session: session
)

try await analytics.log(payload: payload)
```
23 changes: 12 additions & 11 deletions Sources/Analytics/Analytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public struct Analytics<HTTPClient: HTTPClientProtocol> {
self.clientInformation = clientInformation
self.session = session
}

public func log(payload: Payload) async throws {
let payloadData = try ProtobufEncoder.encoding(NestedValue(value: payload))
try await log(bodyData: payloadData)
Expand Down Expand Up @@ -60,23 +60,23 @@ public struct Analytics<HTTPClient: HTTPClientProtocol> {
value: 1,
events: [
EventPayload(
parameters: parameters.merging([.platform: "app"]) { $1 }.compactMapValues { $0 },
eventName: eventName,
parameters: parameters.merging([.platform: "app"]) { $1 }.compactMapValues { $0 },
previousTimestampMillis: UInt(Date.now.timeIntervalSince1970 * 100),
timestampMillis: UInt(Date.now.timeIntervalSince1970 * 100)
),
EventPayload(
parameters: ["_et": .uint(891), .platform: "auto"],
eventName: "_e",
parameters: ["_et": .uint(891), .platform: "auto"],
previousTimestampMillis: UInt(Date.now.timeIntervalSince1970 * 100),
timestampMillis: UInt(Date.now.timeIntervalSince1970 * 100)
),
],
sessionInformations: session.parameters,
value4: UInt(Date.now.timeIntervalSince1970 * 100), // upload_timestamp_millis
value5: UInt(Date.now.timeIntervalSince1970 * 100), // start_timestamp_millis
value6: UInt(Date.now.timeIntervalSince1970 * 100), // end_timestamp_millis
value7: UInt(Date.now.timeIntervalSince1970 * 100), // previous_bundle_end_timestamp_millis
value4: UInt(Date.now.timeIntervalSince1970 * 100), // upload_timestamp_millis
value5: UInt(Date.now.timeIntervalSince1970 * 100), // start_timestamp_millis
value6: UInt(Date.now.timeIntervalSince1970 * 100), // end_timestamp_millis
value7: UInt(Date.now.timeIntervalSince1970 * 100), // previous_bundle_end_timestamp_millis
os: clientInformation.os,
osVersion: clientInformation.osVersion,
deviceModel: clientInformation.deviceModel,
Expand All @@ -85,15 +85,16 @@ public struct Analytics<HTTPClient: HTTPClientProtocol> {
installMethod: clientInformation.installMethod,
bundleId: clientInformation.bundleId,
appVersion: clientInformation.appVersion,
value17: 110700, // gmp_version
value18: 110700, // uploading_gmp_version
value17: 110700, // gmp_version
value18: 110700, // uploading_gmp_version
value21: "BC75E8783E8141ECB7A179248F24080C", // fix // app_instance_id
value23: 25, // count up // bundle_sequential_index
googleAppId: clientInformation.googleAppId,
value26: UInt(Date.now.timeIntervalSince1970 * 100), // free // previous_bundle_start_timestamp_millis
// free // previous_bundle_start_timestamp_millis
value26: UInt(Date.now.timeIntervalSince1970 * 100),
value27: "C86A6B98-E407-4954-BC16-F693A22F9FA9", // fix // resettable_device_id
value30: "d4Xw8qsiRUIBoMYlsYHnot", // fix // firebase_instance_id
value31: 1, // app_version_major
value31: 1, // app_version_major
value35: 1_727_127_969_769_945, // fix // config_version
value45: 42_820_019, // fix
value52: "G1--", // fix // consent_signals
Expand Down
12 changes: 6 additions & 6 deletions Sources/Analytics/Parameter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public enum Parameter {
static func bool(_ value: Bool) -> Self {
.uint(value ? 1 : 0)
}

public init(from decoder: inout ProtobufDecoder) throws {
var value: Parameter.Value?

Expand Down Expand Up @@ -58,17 +58,17 @@ public enum Parameter {

public func encode(to encoder: inout ProtobufEncoder) throws {
switch self {
case let .string(value):
case .string(let value):
try encoder.stringField(1, value, defaultValue: nil)
case let .uint(value):
case .uint(let value):
encoder.uintField(2, value, defaultValue: nil)
case let .float(value):
case .float(let value):
encoder.doubleField(5, value, defaultValue: nil)
case let .dictionary(value):
case .dictionary(let value):
for (key, value) in value {
try encoder.messageField(6, KeyValue(key: key, value: value))
}
case let .array(values):
case .array(let values):
for item in values {
try encoder.messageField(6, item)
}
Expand Down
16 changes: 8 additions & 8 deletions Sources/Analytics/Payload/EventPayload.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import ProtobufKit

public struct EventPayload: ProtobufMessage, Equatable {
public var parameters: [Parameter.Key: Parameter.Value]
public var eventName: Event.Name
public var parameters: [Parameter.Key: Parameter.Value]
public var previousTimestampMillis: UInt?
public var timestampMillis: UInt

public init(
parameters: [Parameter.Key: Parameter.Value],
eventName: Event.Name,
parameters: [Parameter.Key: Parameter.Value],
previousTimestampMillis: UInt?,
timestampMillis: UInt
) {
Expand Down Expand Up @@ -46,8 +46,8 @@ public struct EventPayload: ProtobufMessage, Equatable {

if let eventName, let timestampMillis {
self.init(
parameters: parameters,
eventName: eventName,
parameters: parameters,
previousTimestampMillis: previousTimestampMillis,
timestampMillis: timestampMillis
)
Expand Down Expand Up @@ -99,16 +99,16 @@ struct KeyValue: ProtobufMessage {
func encode(to encoder: inout ProtobufEncoder) throws {
try encoder.stringField(1, key.rawValue, defaultValue: nil)
switch value {
case let .string(value):
case .string(let value):
try encoder.stringField(2, value, defaultValue: nil)
case let .uint(value):
case .uint(let value):
encoder.uintField(3, value, defaultValue: nil)
case let .float(value):
case .float(let value):
encoder.doubleField(5, value, defaultValue: nil)
case let .dictionary(values):
case .dictionary(let values):
let arayValue = Array6(value: .dictionary(values))
try encoder.messageField(6, arayValue)
case let .array(values):
case .array(let values):
for value in values {
let arayValue = Array6(value: value)
try encoder.messageField(6, arayValue)
Expand Down
10 changes: 5 additions & 5 deletions Sources/Analytics/Payload/ValueKeyValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,17 @@ public struct ValueKeyValue: ProtobufMessage, Equatable {
encoder.uintField(1, date, defaultValue: nil)
try encoder.stringField(2, key, defaultValue: nil)
switch value {
case let .string(value):
case .string(let value):
try encoder.stringField(3, value, defaultValue: nil)
case let .uint(value):
case .uint(let value):
encoder.uintField(4, value, defaultValue: nil)
case let .float(value):
case .float(let value):
encoder.doubleField(6, value, defaultValue: nil)
case let .dictionary(values):
case .dictionary(let values):
for item in values {
try encoder.messageField(7, KeyValue(key: item.key, value: item.value))
}
case let .array(values):
case .array(let values):
for item in values {
try encoder.messageField(7, item)
}
Expand Down
1 change: 1 addition & 0 deletions Tests/AnalyticsTests/AnalyticsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@