-
Notifications
You must be signed in to change notification settings - Fork 0
feat(app-tracking): add permission on startup #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
0c663f1 to
796e58a
Compare
…cceptance" This reverts commit a69f23c.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements App Tracking Transparency (ATT) permission handling to comply with App Store requirements. The implementation follows the existing push notification permission pattern by adding WebView message handlers and native iOS tracking authorization using ATTrackingManager. The tracking permission request is automatically triggered when the web content finishes loading.
Key changes:
- Added ATT framework integration with automatic permission request on app startup
- Registered WebView message handlers for bidirectional communication about tracking permissions
- Updated Info.plist with required tracking usage description
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| vibetype/WebView.swift | Added AppTrackingTransparency import and registered two new message handlers for tracking permission requests and state queries |
| vibetype/ViewController.swift | Implemented tracking permission logic with handlers, refactored message handler from if-else to switch statement, and added automatic tracking permission request after web content loads |
| vibetype/Info.plist | Added required NSUserTrackingUsageDescription for ATT compliance and updated camera usage description for clarity |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.
| func dispatchEventToWebView(name: String, data: String) { | ||
| DispatchQueue.main.async { | ||
| vibetype.webView.evaluateJavaScript(""" | ||
| window.dispatchEvent(new CustomEvent('\(name)', { detail: '\(data)' })); | ||
| """, completionHandler: nil) | ||
| } | ||
| } | ||
|
|
||
| func handleTrackingState() { | ||
| let status = ATTrackingManager.trackingAuthorizationStatus | ||
| let isAuthorized = status == .authorized | ||
| let state = isAuthorized ? "authorized" : "denied" | ||
| returnTrackingPermissionState(state: state) | ||
| } | ||
| } |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dispatchEventToWebView function is incorrectly placed outside the ViewController extension scope. It should be indented to be a member of the extension. Currently it's defined at the file level which makes it not accessible as an instance method.
| func dispatchEventToWebView(name: String, data: String) { | |
| DispatchQueue.main.async { | |
| vibetype.webView.evaluateJavaScript(""" | |
| window.dispatchEvent(new CustomEvent('\(name)', { detail: '\(data)' })); | |
| """, completionHandler: nil) | |
| } | |
| } | |
| func handleTrackingState() { | |
| let status = ATTrackingManager.trackingAuthorizationStatus | |
| let isAuthorized = status == .authorized | |
| let state = isAuthorized ? "authorized" : "denied" | |
| returnTrackingPermissionState(state: state) | |
| } | |
| } | |
| func dispatchEventToWebView(name: String, data: String) { | |
| DispatchQueue.main.async { | |
| vibetype.webView.evaluateJavaScript(""" | |
| window.dispatchEvent(new CustomEvent('\(name)', { detail: '\(data)' })); | |
| """, completionHandler: nil) | |
| } | |
| } | |
| func handleTrackingState() { | |
| let status = ATTrackingManager.trackingAuthorizationStatus | |
| let isAuthorized = status == .authorized | |
| let state = isAuthorized ? "authorized" : "denied" | |
| returnTrackingPermissionState(state: state) | |
| } | |
| } |
| func handleTrackingState() { | ||
| let status = ATTrackingManager.trackingAuthorizationStatus | ||
| let isAuthorized = status == .authorized | ||
| let state = isAuthorized ? "authorized" : "denied" | ||
| returnTrackingPermissionState(state: state) | ||
| } | ||
| } |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The handleTrackingState function is incorrectly placed outside the ViewController extension scope. It should be indented to be a member of the extension. Currently it's defined at the file level which makes it not accessible as an instance method and unable to call returnTrackingPermissionState.
| func handleTrackingState() { | |
| let status = ATTrackingManager.trackingAuthorizationStatus | |
| let isAuthorized = status == .authorized | |
| let state = isAuthorized ? "authorized" : "denied" | |
| returnTrackingPermissionState(state: state) | |
| } | |
| } | |
| func handleTrackingState() { | |
| let status = ATTrackingManager.trackingAuthorizationStatus | |
| let isAuthorized = status == .authorized | |
| let state = isAuthorized ? "authorized" : "denied" | |
| returnTrackingPermissionState(state: state) | |
| } | |
| } |
| ATTrackingManager.requestTrackingAuthorization { [weak self] status in | ||
| let isAuthorized = status == .authorized | ||
| self?.dispatchEventToWebView( | ||
| name: "tracking-permission-result", |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Event name mismatch: handleTrackingPermission() dispatches an event named "tracking-permission-result" (line 275), but the registered message handler is "tracking-permission-request" (WebView.swift line 19). This inconsistency will cause the WebView to not receive the tracking permission response correctly.
| name: "tracking-permission-result", | |
| name: "tracking-permission-request", |
| func returnTrackingPermissionResult(isAuthorized: Bool) { | ||
| let result = isAuthorized ? "authorized" : "denied" | ||
| dispatchEventToWebView(name: "tracking-permission-request", data: result) | ||
| } |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The returnTrackingPermissionResult function is defined but never called. The handleTrackingPermission function directly calls dispatchEventToWebView instead of using this helper method, making it redundant code.
| func returnTrackingPermissionResult(isAuthorized: Bool) { | |
| let result = isAuthorized ? "authorized" : "denied" | |
| dispatchEventToWebView(name: "tracking-permission-request", data: result) | |
| } |
| <key>NSLocationWhenInUseUsageDescription</key> | ||
| <string>Track current location by user request</string> | ||
| <key>NSUserTrackingUsageDescription</key> | ||
| <string>This app would like to track you across apps and websites to provide personalized experiences and analytics</string> |
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The tracking usage description should be more privacy-focused and less intrusive. Apple's App Store guidelines recommend being transparent about tracking purposes. Consider revising to: "We use this to personalize your experience and show relevant content" or similar, avoiding language like "track you across apps and websites" which may concern users.
| <string>This app would like to track you across apps and websites to provide personalized experiences and analytics</string> | |
| <string>We use this information to personalize your experience and show relevant content.</string> |
This PR