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
160 changes: 116 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,35 +69,52 @@ struct PreLandingView: View {
/* ... */
.onAppear {
Task {
// 1.- Search for post-install link and proceed if available
guard let result = try? await traceback.postInstallSearchLink(),
let tracebackURL = result.url else {
return
do {
// 1.- Search for post-install link and proceed if available
let result = try await traceback.postInstallSearchLink()
if let tracebackURL = result.url {
proceed(onOpenURL: tracebackURL)
}
} catch {
// Handle error - network issues, configuration problems, etc.
logger.error("Failed to search for post-install link: \(error)")
}
proceed(onOpenURL: tracebackURL)
}
}
.onOpenURL { url in
proceed(onOpenURL: url)
}
}

// This method is to be called from onOpenURL or after post install link search
func proceed(
onOpenURL: URL
) {
// 2.- Grab the correct url
// URL is either a post-install link (detected after app download on onAppear above),
// or an opened url (direct open in installed app)
guard let linkResult = try? traceback.extractLinkFromURL(url),
let linkURL = linkResult.url else {
return assertionFailure("Could not find a valid traceback/universal url in \(url)")
func proceed(onOpenURL url: URL) {
// 2.- Check if this is a Traceback URL
guard traceback.isTracebackURL(url) else {
// Not a Traceback URL, handle it elsewhere
handleDeepLink(linkURL)
return
}

Task {
do {
// 3.- Check if dynamic campaign link exists (resolves the deep link from the URL)
let linkResult = try await traceback.campaignSearchLink(url)

guard let linkURL = linkResult.url else {
// No deep link found in this URL, so we normally continue opening the app Landing screen
return
}

// 4.- Handle the url, opening the right content indicated by linkURL
// Use linkURL to navigate to the appropriate content in your app
// You can also access linkResult.analytics for tracking purposes
handleDeepLink(linkURL)
sendAnalytics(linkResult.analytics)
} catch {
// Handle error - network issues, invalid URL, etc.
logger.error("Failed to resolve campaign link: \(error)")
}
}

// 3.- Handle the url, opening the right content indicated by linkURL
// Use linkURL to navigate to the appropriate content in your app
// You can also access linkResult.analytics for tracking purposes
YOUR CODE HERE
}
}
```
Expand All @@ -114,13 +131,17 @@ class YourAppDelegate: NSObject, UIApplicationDelegate {
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
) -> Bool {
Task {
// 1.- Trigger a search for installation links
// if a link is found successfully, it will be sent to proceed(openURL:) below
guard let result = try? await traceback.postInstallSearchLink(),
let tracebackURL = result.url else {
return
do {
// 1.- Trigger a search for installation links
// if a link is found successfully, it will be sent to proceed(openURL:) below
let result = try await traceback.postInstallSearchLink()
if let tracebackURL = result.url {
proceed(onOpenURL: tracebackURL)
}
} catch {
// Handle error - network issues, configuration problems, etc.
logger.error("Failed to search for post-install link: \(error)")
}
proceed(onOpenURL: tracebackURL)
}
return true
}
Expand All @@ -135,23 +156,36 @@ class YourAppDelegate: NSObject, UIApplicationDelegate {
proceed(onOpenURL: url)
return true
}

// This method is to be called from application(open:options:) or after post install link search
func proceed(
onOpenURL: URL
) {
// 2.- Grab the correct url
// URL is either a post-install link (detected after app launch above),
// or an opened url (direct open in installed app)
guard let linkResult = try? traceback.extractLinkFromURL(url),
let linkURL = linkResult.url else {
return assertionFailure("Could not find a valid traceback/universal url in \(url)")
func proceed(onOpenURL url: URL) {
// 2.- Check if this is a Traceback URL
guard traceback.isTracebackURL(url) else {
// Not a Traceback URL, handle it elsewhere
handleDeepLink(linkURL)
return
}

Task {
do {
// 3.- Check if dynamic campaign link exists (resolves the deep link from the URL)
let linkResult = try await traceback.campaignSearchLink(url)

guard let linkURL = linkResult.url else {
// No deep link found in this URL, so we normally continue opening the app Landing screen
return
}

// 4.- Handle the url, opening the right content indicated by linkURL
// Use linkURL to navigate to the appropriate content in your app
// You can also access linkResult.analytics for tracking purposes
handleDeepLink(linkURL)
sendAnalytics(linkResult.analytics)
} catch {
// Handle error - network issues, invalid URL, etc.
logger.error("Failed to resolve campaign link: \(error)")
}
}

// 3.- Handle the url, opening the right content indicated by linkURL
// Use linkURL to navigate to the appropriate content in your app
// You can also access linkResult.analytics for tracking purposes
YOUR CODE HERE
}
}
```
Expand Down Expand Up @@ -191,12 +225,26 @@ The diagnostics will categorize issues as:

## API Reference

### TracebackSDK Methods

#### `postInstallSearchLink() async throws -> TracebackSDK.Result`
Searches for the deep link that triggered the app installation. Call this once during app launch.

#### `campaignSearchLink(_ url: URL) async throws -> TracebackSDK.Result`
Resolves a Traceback URL opened via Universal Link or custom URL scheme into a deep link.

#### `isTracebackURL(_ url: URL) -> Bool`
Validates if the given URL matches any of the configured Traceback domains.

#### `performDiagnostics()`
Runs comprehensive validation of your Traceback configuration and outputs diagnostic information.

### TracebackSDK.Result

The result object returned by `postInstallSearchLink()` and `extractLinkFromURL()` contains:
The result object returned by `postInstallSearchLink()` and `campaignSearchLink()` contains:

- `url: URL?` - The extracted deep link URL to navigate to
- `matchType: MatchType` - How the link was detected (`.unique`, `.heuristics`, `.ambiguous`, `.intent`, `.none`)
- `matchType: MatchType` - How the link was detected (`.unique`, `.heuristics`, `.ambiguous`, `.intent`, `.none`, `.unknown`)
- `analytics: [TracebackAnalyticsEvent]` - Analytics events you can send to your preferred platform

### TracebackConfiguration
Expand All @@ -220,14 +268,18 @@ public struct TracebackConfiguration {

## Error Handling

The SDK uses Swift's error handling mechanisms:
The SDK uses Swift's error handling mechanisms. Both `postInstallSearchLink()` and `campaignSearchLink()` can throw errors:

### Post-Install Link Search

```swift
do {
let result = try await traceback.postInstallSearchLink()
if let url = result.url {
// Handle successful link detection
handleDeepLink(url)
// Send analytics events
sendAnalytics(result.analytics)
} else {
// No link found - normal app startup
handleNormalStartup()
Expand All @@ -239,6 +291,26 @@ do {
}
```

### Campaign Link Resolution

```swift
do {
let result = try await traceback.campaignSearchLink(url)
if let deepLink = result.url {
// Handle successful link resolution
handleDeepLink(deepLink)
// Send analytics events
sendAnalytics(result.analytics)
} else {
// URL is valid Traceback URL but no deep link found
handleNormalStartup()
}
} catch {
// Handle network or configuration errors
logger.error("Failed to resolve campaign link: \(error)")
}
```

## Troubleshooting

### Common Issues
Expand Down
6 changes: 6 additions & 0 deletions agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Traceback ios is a companion sdk to communicate with traceback firebase extension
This sdk is installed via SPM in other projects

README.md shuold give enough onboarding information

don't make authoring header files or commit messages with agent information
9 changes: 9 additions & 0 deletions e2e/flows/fresh_install.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# fresh_install.yaml

appId: ${BUNDLE_ID}
---
- launchApp
- tapOn: 'Permitir pegar'
- assertVisible:
text: '.*${DESTINATION_URL}'
index: 0
10 changes: 10 additions & 0 deletions e2e/flows/open_link_in_safari.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# flow.yaml

appId: com.apple.mobilesafari
---
- launchApp
- extendedWaitUntil:
visible: "OPEN"
timeout: 10000
- tapOn: "OPEN"
- tapOn: "OK"
80 changes: 80 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Traceback iOS SDK - Sample Applications

This directory contains sample applications demonstrating how to integrate and use the Traceback iOS SDK in different scenarios.

## Available Samples

### [swiftui-basic](./swiftui-basic/)
A basic SwiftUI application demonstrating:
- Standard Traceback SDK configuration
- Post-install link detection
- Universal Link handling with campaign resolution
- Deep link navigation
- Analytics event tracking
- Diagnostics setup

**Best for:** Getting started with Traceback in a SwiftUI project

### Coming Soon

- **uikit-basic** - Basic UIKit implementation
- **advanced-analytics** - Advanced analytics integration
- **custom-domains** - Multiple domain configuration
- **clipboard-disabled** - Privacy-focused setup without clipboard

## Prerequisites

Before running any sample:

1. **Install the Traceback Firebase Extension** in your Firebase project
- Follow instructions at: https://github.com/InQBarna/firebase-traceback-extension

2. **Configure Firebase** for your sample app
- Create an iOS app in your Firebase Console
- Download `GoogleService-Info.plist`

3. **Set up Associated Domains**
- Configure your Apple Developer account
- Enable Associated Domains capability
- Add the Traceback domain from your Firebase extension

## Running a Sample

Each sample includes its own README with specific setup instructions. Generally:

1. Navigate to the sample directory
2. Follow the README to configure Firebase settings
3. Open the `.xcodeproj` or `.xcworkspace` in Xcode
4. Update the bundle identifier and signing team
5. Run the app on a physical device (Universal Links don't work in Simulator)

## Testing Deep Links

### Create a Test Link

Use the Traceback Firebase extension to create a test deep link:

```bash
# Example: Create a link to open /products/123 in your app
https://your-project-traceback.firebaseapp.com/campaign-name?link=myapp://products/123
```

### Test Post-Install Flow

1. Copy the Traceback link to clipboard
2. Delete the app from your device
3. Install and launch the app
4. The app should detect and open the deep link

### Test Campaign Links

1. Send yourself the Traceback link via Messages/Email
2. Open the link with the app already installed
3. The app should resolve and open the deep link

## Need Help?

- Check the main [README](../README.md) for SDK documentation
- Review the [Troubleshooting](../README.md#troubleshooting) section
- Run `traceback.performDiagnostics()` to validate your setup
- Report issues at: https://github.com/InQBarna/traceback-iOS/issues
Loading