Skip to content
Draft
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
8 changes: 8 additions & 0 deletions vibetype.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
595F23AF25CEFBFE0053416C /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595F23A425CEFBFE0053416C /* WebView.swift */; };
6BC0B4AB2ED94D4100E03379 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 6BC0B4AA2ED94D3A00E03379 /* README.md */; };
7692219AF6CB60CE94E971C2 /* Pods_vibetype.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4248D6343DB1391C0EB00BB7 /* Pods_vibetype.framework */; };
936658952F3085DF00CE9A4A /* TrackingTransparency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 936658942F3085DF00CE9A4A /* TrackingTransparency.swift */; };
CDC0FE292388222C002C8D56 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDC0FE252388222B002C8D56 /* Main.storyboard */; };
CDC0FE2A2388222C002C8D56 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDC0FE272388222B002C8D56 /* LaunchScreen.storyboard */; };
DDBCB1142D6C602600313680 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DDBCB1132D6C602600313680 /* GoogleService-Info.plist */; };
Expand All @@ -37,6 +38,7 @@
595F23A325CEFBFE0053416C /* Printer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Printer.swift; path = vibetype/Printer.swift; sourceTree = "<group>"; };
595F23A425CEFBFE0053416C /* WebView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebView.swift; path = vibetype/WebView.swift; sourceTree = "<group>"; };
6BC0B4AA2ED94D3A00E03379 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
936658942F3085DF00CE9A4A /* TrackingTransparency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TrackingTransparency.swift; path = vibetype/TrackingTransparency.swift; sourceTree = "<group>"; };
B3109B700B2E429F9589C698 /* Pods-vibetype.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-vibetype.release.xcconfig"; path = "Target Support Files/Pods-vibetype/Pods-vibetype.release.xcconfig"; sourceTree = "<group>"; };
CDC0FE262388222B002C8D56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = vibetype/Base.lproj/Main.storyboard; sourceTree = "<group>"; };
CDC0FE282388222B002C8D56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = vibetype/Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
Expand Down Expand Up @@ -80,6 +82,7 @@
595F23A125CEFBFE0053416C /* ViewController.swift */,
CDC0FE272388222B002C8D56 /* LaunchScreen.storyboard */,
CDC0FE252388222B002C8D56 /* Main.storyboard */,
936658942F3085DF00CE9A4A /* TrackingTransparency.swift */,
595F23A425CEFBFE0053416C /* WebView.swift */,
30FCACC6A7BF53CD6D9CF6C0 /* Pods */,
59333BAA25CFF706003392A4 /* vibetype.app */,
Expand Down Expand Up @@ -200,10 +203,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-vibetype/Pods-vibetype-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-vibetype/Pods-vibetype-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-vibetype/Pods-vibetype-frameworks.sh\"\n";
Expand All @@ -218,6 +225,7 @@
files = (
595F23AD25CEFBFE0053416C /* AppDelegate.swift in Sources */,
595F23A825CEFBFE0053416C /* SceneDelegate.swift in Sources */,
936658952F3085DF00CE9A4A /* TrackingTransparency.swift in Sources */,
595F23A525CEFBFE0053416C /* Settings.swift in Sources */,
595F23AE25CEFBFE0053416C /* Printer.swift in Sources */,
595F23AC25CEFBFE0053416C /* ViewController.swift in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions vibetype/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
<string>The app allows taking photos of event posters to show interest in the listed events.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>The app allows accessing your location to provide event recommendations based on your area.</string>
<key>NSUserTrackingUsageDescription</key>
<string>This allows us to provide you with personalized content and improve your experience.</string>
<!-- <key>NSMicrophoneUsageDescription</key>
<string>Capture Audio by user request</string> -->
<key>UIApplicationSceneManifest</key>
Expand Down
59 changes: 59 additions & 0 deletions vibetype/TrackingTransparency.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Foundation
import AppTrackingTransparency
import AdSupport

@available(iOS 14, *)
class TrackingTransparencyManager {

// Request ATT permission and return the result via callback
static func requestPermission(completion: @escaping (ATTrackingManager.AuthorizationStatus) -> Void) {
ATTrackingManager.requestTrackingAuthorization { status in
DispatchQueue.main.async {
completion(status)
}
}
}

// Get current tracking authorization status
static func getStatus() -> ATTrackingManager.AuthorizationStatus {
return ATTrackingManager.trackingAuthorizationStatus
}

// Get status as a string representation for JavaScript
static func getStatusString() -> String {
return statusToString(getStatus())
}

// Convert status to string
static func statusToString(_ status: ATTrackingManager.AuthorizationStatus) -> String {
switch status {
case .notDetermined:
return "notDetermined"
case .restricted:
return "restricted"
case .denied:
return "denied"
case .authorized:
return "authorized"
@unknown default:
return "unknown"
}
}

// Get IDFA (Identifier for Advertisers) if authorized
static func getIDFA() -> String? {
guard getStatus() == .authorized else {
return nil
}

let idfa = ASIdentifierManager.shared().advertisingIdentifier

// Apple returns all zeros when tracking is not authorized
let zeroIDFA = UUID(uuidString: "00000000-0000-0000-0000-000000000000")!
guard idfa != zeroIDFA else {
return nil
}

return idfa.uuidString
}
}
75 changes: 75 additions & 0 deletions vibetype/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -246,5 +246,80 @@ extension ViewController: WKScriptMessageHandler {
if message.name == "push-token" {
handleFCMToken()
}
if message.name == "att-request-permission" {
handleATTPermissionRequest()
}
if message.name == "att-get-status" {
handleATTGetStatus()
}
if message.name == "att-get-idfa" {
handleATTGetIDFA()
}
}
}

// MARK: - App Tracking Transparency Handlers
extension ViewController {

// Helper method to dispatch ATT events to webview with proper JSON serialization
private func dispatchATTEvent(eventName: String, detail: [String: Any]) {
guard let jsonData = try? JSONSerialization.data(withJSONObject: detail),
let jsonString = String(data: jsonData, encoding: .utf8) else {
print("Error serializing ATT response for event: \(eventName)")
return
}
let script = """
window.dispatchEvent(new CustomEvent('\(eventName)', {
detail: \(jsonString)
}));
"""
vibetype.webView.evaluateJavaScript(script) { result, error in
if let error = error {
print("Error dispatching \(eventName): \(error)")
}
}
}

func handleATTPermissionRequest() {
if #available(iOS 14, *) {
TrackingTransparencyManager.requestPermission { status in
let statusString = TrackingTransparencyManager.statusToString(status)
let detail: [String: Any] = ["status": statusString]
self.dispatchATTEvent(eventName: "attPermissionResponse", detail: detail)
}
} else {
// ATT is only available on iOS 14+
let detail: [String: Any] = ["status": "unavailable", "error": "ATT requires iOS 14 or later"]
dispatchATTEvent(eventName: "attPermissionResponse", detail: detail)
}
}

func handleATTGetStatus() {
if #available(iOS 14, *) {
let statusString = TrackingTransparencyManager.getStatusString()
let detail: [String: Any] = ["status": statusString]
dispatchATTEvent(eventName: "attStatusResponse", detail: detail)
} else {
// ATT is only available on iOS 14+
let detail: [String: Any] = ["status": "unavailable"]
dispatchATTEvent(eventName: "attStatusResponse", detail: detail)
}
}

func handleATTGetIDFA() {
if #available(iOS 14, *) {
let idfa = TrackingTransparencyManager.getIDFA()
var detail: [String: Any] = [:]
if let idfa = idfa {
detail["idfa"] = idfa
} else {
detail["idfa"] = NSNull()
}
dispatchATTEvent(eventName: "attIDFAResponse", detail: detail)
} else {
// ATT is only available on iOS 14+
let detail: [String: Any] = ["idfa": NSNull(), "error": "ATT requires iOS 14 or later"]
dispatchATTEvent(eventName: "attIDFAResponse", detail: detail)
}
}
}
3 changes: 3 additions & 0 deletions vibetype/WebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ func createWebView(container: UIView, WKSMH: WKScriptMessageHandler, WKND: WKNav
userContentController.add(WKSMH, name: "push-permission-request")
userContentController.add(WKSMH, name: "push-permission-state")
userContentController.add(WKSMH, name: "push-token")
userContentController.add(WKSMH, name: "att-request-permission")
userContentController.add(WKSMH, name: "att-get-status")
userContentController.add(WKSMH, name: "att-get-idfa")

config.userContentController = userContentController

Expand Down