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
4 changes: 2 additions & 2 deletions .github/workflows/cocoapods-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# This workflow publishes all five podspecs in dependency order:
# 1. KlaviyoCore (foundation, no dependencies)
# 2. KlaviyoSwiftExtension (standalone, no dependencies)
# 2. KlaviyoSwiftExtension (depends on KlaviyoCore)
# 3. KlaviyoSwift (depends on KlaviyoCore)
# 4. KlaviyoForms (depends on KlaviyoSwift)
# 5. KlaviyoLocation (depends on KlaviyoSwift)
Expand Down Expand Up @@ -43,7 +43,7 @@ jobs:
run: |
echo "Validating all podspecs in dependency order..."
pod lib lint KlaviyoCore.podspec --allow-warnings
pod lib lint KlaviyoSwiftExtension.podspec --allow-warnings
pod lib lint KlaviyoSwiftExtension.podspec --allow-warnings --include-podspecs='*.podspec'
pod lib lint KlaviyoSwift.podspec --allow-warnings --include-podspecs='*.podspec'
pod lib lint KlaviyoForms.podspec --allow-warnings --include-podspecs='*.podspec'
pod lib lint KlaviyoLocation.podspec --allow-warnings --include-podspecs='*.podspec'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.cocoapods.example.NotificationServiceExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
Expand Down Expand Up @@ -508,7 +508,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.cocoapods.example.NotificationServiceExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
Expand Down Expand Up @@ -654,7 +654,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.cocoapods.example;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down Expand Up @@ -687,7 +687,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.cocoapods.example;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -705,7 +705,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = G3793W2RJ2;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.cocoapods.example.CocoapodsExampleUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -723,7 +723,7 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = G3793W2RJ2;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.cocoapods.example.CocoapodsExampleUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand Down
8 changes: 4 additions & 4 deletions Examples/KlaviyoSwiftExamples/CocoapodsExample/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ platform :ios, '13.0'
use_frameworks!

target 'CocoapodsExample' do
pod 'KlaviyoSwift', '5.2.2'
pod 'KlaviyoForms', '5.2.2'
pod 'KlaviyoLocation', '5.2.2'
pod 'KlaviyoSwift', '5.3.0'
pod 'KlaviyoForms', '5.3.0'
pod 'KlaviyoLocation', '5.3.0'
end

target 'NotificationServiceExtension' do
pod 'KlaviyoSwiftExtension', '5.2.2'
pod 'KlaviyoSwiftExtension', '5.3.0'
end
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.spm.example.SPMExample.NotificationServiceExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
Expand All @@ -458,7 +458,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.spm.example.SPMExample.NotificationServiceExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
Expand Down Expand Up @@ -609,7 +609,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.spm.example.SPMExample;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down Expand Up @@ -641,7 +641,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.spm.example.SPMExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -659,7 +659,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.spm.example.SPMExampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -677,7 +677,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.spm.example.SPMExampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -693,7 +693,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.spm.example.SPMExampleUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -709,7 +709,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 5.2.2;
MARKETING_VERSION = 5.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.klaviyo.spm.example.SPMExampleUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand Down
17 changes: 9 additions & 8 deletions Examples/KlaviyoSwiftExamples/Shared/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
.initialize(with: "YOUR_PUBLIC_API_KEY")
.registerForInAppForms() // STEP2A: register for in app forms
.registerGeofencing() // STEP2B: register for in geofencing
.registerFormLifecycleHandler { event, context in
.registerFormLifecycleHandler { event in
// STEP2C: [OPTIONAL] Register for form lifecycle events to track form interactions
// This handler is called whenever a form is shown, dismissed, or a CTA is clicked

switch event {
case .formShown:
print("🎨 [Form Lifecycle] Form Shown: \(context.formId ?? "unknown")")
print(" Form Name: \(context.formName ?? "unknown")")
print("🎨 [Form Lifecycle] Form Shown: \(event.formId)")
print(" Form Name: \(event.formName)")
case .formDismissed:
print("👋 [Form Lifecycle] Form Dismissed: \(context.formId ?? "unknown")")
print(" Form Name: \(context.formName ?? "unknown")")
case .formCTAClicked:
print("🖱️ [Form Lifecycle] Form CTA Clicked: \(context.formId ?? "unknown")")
print(" Form Name: \(context.formName ?? "unknown")")
print("👋 [Form Lifecycle] Form Dismissed: \(event.formId)")
print(" Form Name: \(event.formName)")
case let .formCtaClicked(_, _, buttonLabel, deepLinkUrl):
print("🖱️ [Form Lifecycle] Form CTA Clicked: \(event.formId)")
print(" Form Name: \(event.formName)")
print(" Button: \(buttonLabel) → \(deepLinkUrl)")
}
}

Expand Down
2 changes: 1 addition & 1 deletion KlaviyoCore.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "KlaviyoCore"
s.version = "5.2.3"
s.version = "5.3.0"
s.summary = "Core functionalities for the Klaviyo SDK"
s.description = <<-DESC
Core functionalities and utilities for the Klaviyo SDK.
Expand Down
4 changes: 2 additions & 2 deletions KlaviyoForms.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "KlaviyoForms"
s.version = "5.2.3"
s.version = "5.3.0"
s.summary = "Klaviyo forms is a new way to engage with your app users"
s.description = <<-DESC
Use Klaviyo forms to include in app forms in your app and engage user with marketing content
Expand All @@ -19,5 +19,5 @@ Pod::Spec.new do |s|
]
}
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-package-name KlaviyoSwift -package-name KlaviyoCore' }
s.dependency 'KlaviyoSwift', '~> 5.2.3'
s.dependency 'KlaviyoSwift', '~> 5.3.0'
end
4 changes: 2 additions & 2 deletions KlaviyoLocation.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "KlaviyoLocation"
s.version = "5.2.3"
s.version = "5.3.0"
s.summary = "Location services and geofencing for the Klaviyo SDK"
s.description = <<-DESC
Use KlaviyoLocation to enable location-based tracking and geofencing capabilities in your iOS applications.
Expand All @@ -14,6 +14,6 @@ Pod::Spec.new do |s|
s.platform = :ios, '13.0'
s.source_files = 'Sources/KlaviyoLocation/**/*.swift'
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-package-name KlaviyoLocation -package-name KlaviyoSwift -package-name KlaviyoCore' }
s.dependency 'KlaviyoSwift', '~> 5.2.3'
s.dependency 'KlaviyoSwift', '~> 5.3.0'
s.frameworks = 'CoreLocation'
end
4 changes: 2 additions & 2 deletions KlaviyoSwift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "KlaviyoSwift"
s.version = "5.2.3"
s.version = "5.3.0"
s.summary = "Incorporate Klaviyo's event and person tracking and push notifications functionality into iOS applications"

s.description = <<-DESC
Expand All @@ -17,6 +17,6 @@ Pod::Spec.new do |s|
s.source_files = 'Sources/KlaviyoSwift/**/*.swift'
s.resource_bundles = {"KlaviyoSwift" => ["Sources/KlaviyoSwift/PrivacyInfo.xcprivacy"]}
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-package-name KlaviyoSwift -package-name KlaviyoCore' }
s.dependency 'KlaviyoCore', '~> 5.2.3'
s.dependency 'KlaviyoCore', '~> 5.3.0'
s.dependency 'AnyCodable-FlightSchool'
end
3 changes: 2 additions & 1 deletion KlaviyoSwiftExtension.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "KlaviyoSwiftExtension"
s.version = "5.2.3"
s.version = "5.3.0"
Comment thread
cursor[bot] marked this conversation as resolved.
s.summary = "Incorporate Klaviyo's rich push notifications functionality into your iOS applications"

s.description = <<-DESC
Expand All @@ -15,4 +15,5 @@ Pod::Spec.new do |s|
s.platform = :ios
s.ios.deployment_target = '13.0'
s.source_files = 'Sources/KlaviyoSwiftExtension/**/*.swift'
s.dependency 'KlaviyoCore', '~> 5.3.0'
end
9 changes: 8 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,16 @@ let package = Package(
),
.target(
name: "KlaviyoSwiftExtension",
dependencies: [],
dependencies: ["KlaviyoCore"],
path: "Sources/KlaviyoSwiftExtension"
),
.testTarget(
name: "KlaviyoSwiftExtensionTests",
dependencies: [
"KlaviyoSwiftExtension",
"KlaviyoCore"
]
),
.target(
name: "KlaviyoLocation",
dependencies: [
Expand Down
49 changes: 48 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
- [Autoclearing](#autoclearing)
- [Handling Other Badging Sources](#handling-other-badging-sources)
- [Silent Push Notifications](#silent-push-notifications)
- [Handling background notifications (content-available)](#handling-background-notifications-content-available)
- [Custom Data](#custom-data)
- [Push Action Buttons](#push-action-buttons)
- [Deep Linking](#deep-linking)
- [Adding link-handling logic](#adding-link-handling-logic)
- [Handling URL Schemes](#handling-url-schemes)
Expand Down Expand Up @@ -427,7 +429,7 @@ func application(_ application: UIApplication, didReceiveRemoteNotification user
// Access custom key-value pairs from the top level
if let customData = userInfo["key_value_pairs"] as? [String: String] {
// Process your custom key-value pairs here
for (key, value) in kvPairs {
for (key, value) in customData {
print("Key: \(key), Value: \(value)")
}
} else {
Expand All @@ -438,9 +440,54 @@ func application(_ application: UIApplication, didReceiveRemoteNotification user

> ℹ️ Silent push notifications are not supported by the iOS simulator. To test silent push notifications, please use a real device.

#### Handling background notifications (content-available)

Klaviyo can send a **standard** push (title, body, and other visible notification UI) whose APNs payload also includes **`content-available: 1`**. That is different from a [silent push](#silent-push-notifications): silent pushes never show an alert, while this is a normal user-visible notification that *additionally* asks iOS to wake your app in the background so you can refresh data or run other work from the same `userInfo`.

You still handle the visible notification through [`UNUserNotificationCenterDelegate`](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate) when the message is presented or opened. The background wake for `content-available` uses the same app delegate path as silent push: `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`. Implement that method (see the example under [Silent Push Notifications](#silent-push-notifications)) and finish by calling `completionHandler` with `.newData`, `.noData`, or `.failed` when your background work completes. Use the same Background Modes / remote-notification setup called out in that section (Apple’s [background updates](https://developer.apple.com/documentation/usernotifications/pushing-background-updates-to-your-app) guide).

> ℹ️ Background wakes are best-effort and may be throttled. As with [silent push notifications](#silent-push-notifications), test this functionality on a physical device because the Simulator does not support the full remote-notification background path.

#### Custom Data
Klaviyo messages can also include key-value pairs (custom data) for both standard and silent push notifications. You can access these key-value pairs using the `key_value_pairs` key on the [`userInfo`](https://developer.apple.com/documentation/foundation/nsnotification/1409222-userinfo) dictionary associated with the notification (for silent pushes, see the example above; for standard pushes, see [`NotificationService.swift`](https://github.com/klaviyo/klaviyo-swift-sdk/blob/master/Examples/KlaviyoSwiftExamples/SPMExample/NotificationServiceExtension/NotificationService.swift) in the example app). This enables you to extract additional information from the push payload and handle it appropriately - for instance, by triggering background processing, logging analytics events, or dynamically updating app content.

#### Push Action Buttons

> ℹ️ Push Action Buttons is supported in SDK version [5.3.0](https://github.com/klaviyo/klaviyo-swift-sdk/releases/tag/5.3.0) and higher

Klaviyo supports the ability to add [custom push action buttons](https://help.klaviyo.com/hc/en-us/article/46285872166683) to push notification messages. These buttons can show custom text and can deep link or open your app when tapped. If a button is tapped, the open push event includes the corresponding button information. No additional setup is needed to support push action buttons. Push notifications can include a maximum of 3 valid buttons.

To test push action buttons, use Apple's official [push notification console](https://developer.apple.com/notifications/push-notifications-console/) or a third party software such as [this](https://github.com/onmyway133/PushNotifications) and send a payload with this format to resemble what the SDK would receive from Klaviyo.

```json
{
"aps": {
"alert": {
"title": "New Arrivals Just for You",
"body": "Check out our latest collection"
},
"mutable-content": 1,
"sound": "default"
},
"body": {
"_k": { },
"action_buttons": [
{
"id": "someId",
"label": "Go to Settings",
"action": "deep_link",
"url": "klaviyotest://settings"
},
{
"id": "someOtherId",
"label": "Open App",
"action": "open_app"
}
]
}
}
```

## Deep Linking

Klaviyo [Deep Links](https://help.klaviyo.com/hc/en-us/articles/14750403974043) allow you to navigate to a particular page within your app in response to the user opening a push notification, tapping an In-App Form link, or by tapping a universal link from outside of the app. The Klaviyo Swift SDK supports deep linking using either URL schemes or universal links.
Expand Down
Loading
Loading