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
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>Your device's advertising identifier will be used by Google Analytics to measure and analyze app usage across apps and websites, helping us understand how our service is being used and improve it for all users.</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
}
}
65 changes: 62 additions & 3 deletions vibetype/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,20 +231,79 @@ extension UIColor {

extension ViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "att-get-idfa" {
handleATTGetIDFA()
}
if message.name == "att-get-status" {
handleATTGetStatus()
}
if message.name == "att-request-permission" {
handleATTPermissionRequest()
}
if message.name == "print" {
printView(webView: vibetype.webView)
}
if message.name == "push-subscribe" {
handleSubscribeTouch(message: message)
}
if message.name == "push-permission-request" {
handlePushPermission()
}
if message.name == "push-permission-state" {
handlePushState()
}
if message.name == "push-subscribe" {
handleSubscribeTouch(message: message)
}
if message.name == "push-token" {
handleFCMToken()
}
}
}

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

private func dispatchATTEvent(eventName: String, detail: String) {
func toJsonString(_ value: String) -> String? {
guard let data = try? JSONSerialization.data(withJSONObject: [value]),
let json = String(data: data, encoding: .utf8) else { return nil }
return String(json.dropFirst().dropLast()) // strip wrapping [ and ]
}
guard let detailJson = toJsonString(detail),
let eventNameJson = toJsonString(eventName) else {
print("Error encoding ATT event data for: \(eventName)")
return
}
let script = "window.dispatchEvent(new CustomEvent(\(eventNameJson), { detail: \(detailJson) }));"
vibetype.webView.evaluateJavaScript(script) { _, error in
if let error = error {
print("Error dispatching \(eventName): \(error)")
}
}
}

func handleATTPermissionRequest() {
if #available(iOS 14, *) {
TrackingTransparencyManager.requestPermission { [weak self] status in
guard let self else { return }
self.dispatchATTEvent(eventName: "att-permission-response", detail: TrackingTransparencyManager.statusToString(status))
}
} else {
dispatchATTEvent(eventName: "att-permission-response", detail: "unavailable")
}
}

func handleATTGetStatus() {
if #available(iOS 14, *) {
dispatchATTEvent(eventName: "att-status-response", detail: TrackingTransparencyManager.getStatusString())
} else {
dispatchATTEvent(eventName: "att-status-response", detail: "unavailable")
}
}

func handleATTGetIDFA() {
if #available(iOS 14, *) {
dispatchATTEvent(eventName: "att-idfa-response", detail: TrackingTransparencyManager.getIDFA() ?? "")
} else {
dispatchATTEvent(eventName: "att-idfa-response", detail: "")
}
}
}
30 changes: 23 additions & 7 deletions vibetype/WebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,35 @@ import WebKit
import AuthenticationServices
import SafariServices

final class WeakScriptMessageHandler: NSObject, WKScriptMessageHandler {
private weak var delegate: AnyObject?

func createWebView(container: UIView, WKSMH: WKScriptMessageHandler, WKND: WKNavigationDelegate, NSO: NSObject, VC: ViewController) -> WKWebView{
init(delegate: AnyObject & WKScriptMessageHandler) {
self.delegate = delegate
super.init()
}

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
(delegate as? WKScriptMessageHandler)?.userContentController(userContentController, didReceive: message)
}
}

func createWebView(container: UIView, WKSMH: AnyObject & WKScriptMessageHandler, WKND: WKNavigationDelegate, NSO: NSObject, VC: ViewController) -> WKWebView{

let config = WKWebViewConfiguration()
let userContentController = WKUserContentController()
let deviceModel = UIDevice.current.model
let osVersion = ProcessInfo().operatingSystemVersion

userContentController.add(WKSMH, name: "print")
userContentController.add(WKSMH, name: "push-subscribe")
userContentController.add(WKSMH, name: "push-permission-request")
userContentController.add(WKSMH, name: "push-permission-state")
userContentController.add(WKSMH, name: "push-token")
let weakHandler = WeakScriptMessageHandler(delegate: WKSMH)

userContentController.add(weakHandler, name: "att-get-idfa")
userContentController.add(weakHandler, name: "att-get-status")
userContentController.add(weakHandler, name: "att-request-permission")
userContentController.add(weakHandler, name: "print")
userContentController.add(weakHandler, name: "push-permission-request")
userContentController.add(weakHandler, name: "push-permission-state")
userContentController.add(weakHandler, name: "push-subscribe")
userContentController.add(weakHandler, name: "push-token")

config.userContentController = userContentController

Expand Down
Loading