Skip to content

Commit

Permalink
Improve countImpression functionality in native ios
Browse files Browse the repository at this point in the history
  • Loading branch information
slawomirzaba committed Dec 16, 2024
1 parent a5ae9fa commit 2cd9805
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 19 deletions.
2 changes: 1 addition & 1 deletion ContentPassExample/ContentPassExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ struct ContentView: View {
viewModel.countImpression()
}
.buttonStyle(.borderedProminent)
.opacity(viewModel.isError || !viewModel.isAuthenticated ? 0 : 1)
.opacity(viewModel.isError ? 0 : 1)
}
}
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,10 @@ Since we don't monitor the device's connection state you need to tell the SDK th
contentPass.recoverFromError()
```

### Couting an impression

Counting an impression is as easy as calling the function `countImpression(completionHandler:)`. A user has to be authenticated and have an active subscription applicable to your scope for this to work.
### Counting an impression
`countImpression` method tracks and increments the impression count for the current user. This method should be invoked whenever
a user views a piece of content. It applies to all users, whether authenticated or unauthenticated.
Counting an impression is as easy as calling the function `countImpression(completionHandler:)`.

```swift
contentPass.countImpression { result in
Expand Down
106 changes: 91 additions & 15 deletions Sources/ContentPass/ContentPass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import AppAuth
import AuthenticationServices
import UIKit

let samplingRate: Double = 0.05

/// Functions that enable you to react to changes in the contentpass sdk's state.
public protocol ContentPassDelegate: AnyObject {
/// A function that enables you to react to a change in contentpass state.
Expand Down Expand Up @@ -134,26 +136,39 @@ public class ContentPass: NSObject {
validateAuthState()
}

/// Count an impression for the logged in user.
/// Count an impression for user.
///
/// A user needs to be authenticated and have a subscription applicable to your service.
/// - Parameter completionHandler: On a successful counting of the impression, the Result is a `success`. If something went wrong, you'll be supplied with an appropriate error case. The error `ContentPassError.badHTTPStatusCode(404)` most probably means that your user has no applicable subscription.
/// If user has a valid subscription, a paid impression will be counted. Additionally a sampled impression will be
/// counted for all users, no matter if they have a valid subscription or not.
/// - Parameter completionHandler: On a successful counting of the impression, the Result is a `success`. If something went wrong,
/// you'll be supplied with an appropriate error case.
public func countImpression(completionHandler: @escaping (Result<Void, Error>) -> Void) {
let impressionID = UUID()
let propertyId = propertyId.split(separator: "-").first!
let request = URLRequest(url: URL(string: "\(configuration.apiUrl)/pass/hit?pid=\(propertyId)&iid=\(impressionID)&t=pageview")!)
let dispatchGroup = DispatchGroup()
var errors: [Error] = []

if state == .authenticated(hasValidSubscription: true) {
dispatchGroup.enter()
countPaidImpression { result in
if case .failure(let error) = result {
errors.append(error)
}
dispatchGroup.leave()
}
}

oidAuthState?.fireRequest(urlRequest: request) { _, response, error in
if let error = error {
dispatchGroup.enter()
countSampledImpression { result in
if case .failure(let error) = result {
errors.append(error)
}
dispatchGroup.leave()
}

dispatchGroup.notify(queue: .main) {
if let error = errors.first {
completionHandler(.failure(error))
} else if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(.success(()))
} else {
completionHandler(.failure(ContentPassError.badHTTPStatusCode(httpResponse.statusCode)))
}
} else {
completionHandler(.failure(ContentPassError.corruptedResponseFromWeb))
completionHandler(.success(()))
}
}
}
Expand Down Expand Up @@ -190,6 +205,67 @@ public class ContentPass: NSObject {
super.init()
}

private func countPaidImpression(completionHandler: @escaping (Result<Void, Error>) -> Void) {
let impressionID = UUID()
let propertyId = propertyId.split(separator: "-").first!
let request = URLRequest(url: URL(string: "\(configuration.apiUrl)/pass/hit?pid=\(propertyId)&iid=\(impressionID)&t=pageview")!)

oidAuthState?.fireRequest(urlRequest: request) { _, response, error in
if let error = error {
completionHandler(.failure(error))
} else if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(.success(()))
} else {
completionHandler(.failure(ContentPassError.badHTTPStatusCode(httpResponse.statusCode)))
}
} else {
completionHandler(.failure(ContentPassError.corruptedResponseFromWeb))
}
}
}

private func countSampledImpression(completionHandler: @escaping (Result<Void, Error>) -> Void) {
let generatedSample = Double.random(in: 0...1)
if generatedSample >= samplingRate {
completionHandler(.success(()))
return
}

let instanceId = UUID().uuidString
let publicId = propertyId.prefix(8)
var request = URLRequest(url: URL(string: "\(configuration.apiUrl)/stats")!)
request.httpMethod="POST"
request.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
let body: [String: Any] = [
"ea": "load",
"ec": "tcf-sampled",
"cpabid": instanceId,
"cppid": publicId,
"cpsr": samplingRate
]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: body)
} catch {
completionHandler(.failure(error))
return
}

URLSession.shared.dataTask(with: request) {_, response, error in
if let error = error {
completionHandler(.failure(error))
} else if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 {
completionHandler(.success(()))
} else {
completionHandler(.failure(ContentPassError.badHTTPStatusCode(httpResponse.statusCode)))
}
} else {
completionHandler(.failure(ContentPassError.corruptedResponseFromWeb))
}
}.resume()
}

private func validateAuthState() {
guard
let authState = oidAuthState,
Expand Down

0 comments on commit 2cd9805

Please sign in to comment.