Skip to content

Commit 0b4ca92

Browse files
committed
add live activities to new demo
1 parent 8fddfc5 commit 0b4ca92

13 files changed

Lines changed: 686 additions & 1 deletion

iOS_SDK/OneSignalSwiftUIExample/OneSignalSwiftUIExample.xcodeproj/project.pbxproj

Lines changed: 176 additions & 0 deletions
Large diffs are not rendered by default.

iOS_SDK/OneSignalSwiftUIExample/OneSignalSwiftUIExample/App/OneSignalSwiftUIExampleApp.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ struct OneSignalSwiftUIExampleApp: App {
3737
WindowGroup {
3838
ContentView()
3939
.environmentObject(viewModel)
40+
.onOpenURL { url in
41+
let originalURL = OneSignal.LiveActivities.trackClickAndReturnOriginal(url)
42+
LogManager.shared.i("LiveActivity", "Opened with URL: \(url), original: \(String(describing: originalURL))")
43+
}
4044
}
4145
}
4246
}
@@ -64,6 +68,11 @@ class AppDelegate: NSObject, UIApplicationDelegate {
6468
// Initialize OneSignal
6569
OneSignalService.shared.initialize(launchOptions: launchOptions)
6670

71+
// Start Live Activity listeners
72+
if #available(iOS 16.1, *) {
73+
LiveActivityController.start()
74+
}
75+
6776
// Restore cached SDK states before UI loads
6877
restoreCachedStates()
6978

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#if targetEnvironment(macCatalyst)
2+
#else
3+
import ActivityKit
4+
import OneSignalLiveActivities
5+
6+
struct ExampleAppFirstWidgetAttributes: OneSignalLiveActivityAttributes {
7+
public struct ContentState: OneSignalLiveActivityContentState {
8+
var message: String
9+
var onesignal: OneSignalLiveActivityContentStateData?
10+
}
11+
12+
var title: String
13+
var onesignal: OneSignalLiveActivityAttributeData
14+
}
15+
16+
struct ExampleAppSecondWidgetAttributes: OneSignalLiveActivityAttributes {
17+
public struct ContentState: OneSignalLiveActivityContentState {
18+
var message: String
19+
var status: String
20+
var progress: Double
21+
var bugs: Int
22+
var onesignal: OneSignalLiveActivityContentStateData?
23+
}
24+
25+
var title: String
26+
var onesignal: OneSignalLiveActivityAttributeData
27+
}
28+
29+
struct ExampleAppThirdWidgetAttributes: ActivityAttributes {
30+
public struct ContentState: Codable, Hashable {
31+
var message: String
32+
}
33+
34+
var title: String
35+
var isPushToStart: Bool
36+
}
37+
#endif

iOS_SDK/OneSignalSwiftUIExample/OneSignalSwiftUIExample/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
<key>UIApplicationSupportsMultipleScenes</key>
3030
<false/>
3131
</dict>
32+
<key>NSSupportsLiveActivities</key>
33+
<true/>
3234
<key>UIBackgroundModes</key>
3335
<array>
3436
<string>remote-notification</string>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import Foundation
2+
import OneSignalFramework
3+
#if targetEnvironment(macCatalyst)
4+
#else
5+
import ActivityKit
6+
import OneSignalLiveActivities
7+
8+
class LiveActivityController {
9+
10+
@available(iOS 16.1, *)
11+
static func start() {
12+
OneSignal.LiveActivities.setup(ExampleAppFirstWidgetAttributes.self)
13+
OneSignal.LiveActivities.setup(ExampleAppSecondWidgetAttributes.self)
14+
OneSignal.LiveActivities.setupDefault()
15+
16+
if #available(iOS 17.2, *) {
17+
Task {
18+
for try await data in Activity<ExampleAppThirdWidgetAttributes>.pushToStartTokenUpdates {
19+
let token = data.map { String(format: "%02x", $0) }.joined()
20+
OneSignal.LiveActivities.setPushToStartToken(ExampleAppThirdWidgetAttributes.self, withToken: token)
21+
}
22+
}
23+
Task {
24+
for await activity in Activity<ExampleAppThirdWidgetAttributes>.activityUpdates
25+
where activity.attributes.isPushToStart {
26+
Task {
27+
for await pushToken in activity.pushTokenUpdates {
28+
let token = pushToken.map { String(format: "%02x", $0) }.joined()
29+
OneSignal.LiveActivities.enter("my-activity-id", withToken: token)
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}
36+
37+
static var counter1 = 0
38+
39+
@available(iOS 16.1, *)
40+
static func createOneSignalAwareActivity(activityId: String) {
41+
counter1 += 1
42+
let oneSignalAttribute = OneSignalLiveActivityAttributeData.create(activityId: activityId)
43+
let attributes = ExampleAppFirstWidgetAttributes(title: "#\(counter1) Live Activity", onesignal: oneSignalAttribute)
44+
let contentState = ExampleAppFirstWidgetAttributes.ContentState(message: "Update this message through push")
45+
do {
46+
_ = try Activity<ExampleAppFirstWidgetAttributes>.request(
47+
attributes: attributes,
48+
contentState: contentState,
49+
pushType: .token)
50+
} catch {
51+
print(error.localizedDescription)
52+
}
53+
}
54+
55+
@available(iOS 16.1, *)
56+
static func createDefaultActivity(activityId: String) {
57+
let attributeData: [String: Any] = ["title": "in-app-title"]
58+
let contentData: [String: Any] = ["message": ["en": "HELLO", "es": "HOLA"], "progress": 0.58, "status": "1/15", "bugs": 2]
59+
OneSignal.LiveActivities.startDefault(activityId, attributes: attributeData, content: contentData)
60+
}
61+
62+
static var counter2 = 0
63+
64+
@available(iOS 16.1, *)
65+
static func createActivity(activityId: String) async {
66+
counter2 += 1
67+
let attributes = ExampleAppThirdWidgetAttributes(title: "#\(counter2) Live Activity", isPushToStart: false)
68+
let contentState = ExampleAppThirdWidgetAttributes.ContentState(message: "Update this message through push")
69+
do {
70+
let activity = try Activity<ExampleAppThirdWidgetAttributes>.request(
71+
attributes: attributes,
72+
contentState: contentState,
73+
pushType: .token)
74+
for await data in activity.pushTokenUpdates {
75+
let myToken = data.map { String(format: "%02x", $0) }.joined()
76+
OneSignal.LiveActivities.enter(activityId, withToken: myToken)
77+
}
78+
} catch {
79+
print(error.localizedDescription)
80+
}
81+
}
82+
}
83+
#endif

iOS_SDK/OneSignalSwiftUIExample/OneSignalSwiftUIExample/ViewModels/OneSignalViewModel.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,32 @@ final class OneSignalViewModel: ObservableObject {
418418
showToast("Location permission requested")
419419
}
420420

421+
// MARK: - Live Activities
422+
423+
func enterLiveActivity(activityId: String) {
424+
let id = activityId.trimmingCharacters(in: .whitespacesAndNewlines)
425+
guard !id.isEmpty else {
426+
showToast("Please enter an activity ID")
427+
return
428+
}
429+
if #available(iOS 16.1, *) {
430+
LiveActivityController.createOneSignalAwareActivity(activityId: id)
431+
showToast("Live Activity '\(id)' entered")
432+
} else {
433+
showToast("Live Activities require iOS 16.1+")
434+
}
435+
}
436+
437+
func exitLiveActivity(activityId: String) {
438+
let id = activityId.trimmingCharacters(in: .whitespacesAndNewlines)
439+
guard !id.isEmpty else {
440+
showToast("Please enter an activity ID")
441+
return
442+
}
443+
OneSignal.LiveActivities.exit(id)
444+
showToast("Live Activity '\(id)' exited")
445+
}
446+
421447
// MARK: - Notifications
422448

423449
func clearAllNotifications() {

iOS_SDK/OneSignalSwiftUIExample/OneSignalSwiftUIExample/Views/ContentView.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ struct ContentView: View {
8181
// 14. Location
8282
LocationSection()
8383

84-
// 15. Next Activity
84+
// 15. Live Activities
85+
LiveActivitySection()
86+
87+
// 16. Next Activity
8588
NextScreenSection()
8689
}
8790
.padding(.horizontal, 16)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import SwiftUI
2+
import OneSignalFramework
3+
4+
struct LiveActivitySection: View {
5+
@EnvironmentObject var viewModel: OneSignalViewModel
6+
@State private var activityId: String = ""
7+
8+
var body: some View {
9+
VStack(spacing: 0) {
10+
SectionHeader(title: "Live Activities", tooltipKey: "liveActivities")
11+
12+
CardContainer {
13+
HStack {
14+
Text("Activity ID")
15+
.font(.system(size: 15, weight: .medium))
16+
.foregroundColor(.secondary)
17+
Spacer()
18+
TextField("Enter activity ID", text: $activityId)
19+
.font(.system(size: 15))
20+
.multilineTextAlignment(.trailing)
21+
.autocorrectionDisabled()
22+
.textInputAutocapitalization(.never)
23+
}
24+
.padding(.horizontal, 16)
25+
.padding(.vertical, 12)
26+
}
27+
28+
ActionButton(title: "Enter Live Activity") {
29+
viewModel.enterLiveActivity(activityId: activityId)
30+
}
31+
.padding(.top, 12)
32+
33+
OutlineActionButton(title: "Exit Live Activity") {
34+
viewModel.exitLiveActivity(activityId: activityId)
35+
}
36+
.padding(.top, 8)
37+
}
38+
}
39+
}
40+
41+
#Preview {
42+
LiveActivitySection()
43+
.padding()
44+
.background(Color(.systemGroupedBackground))
45+
.environmentObject(OneSignalViewModel())
46+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.security.app-sandbox</key>
6+
<true/>
7+
<key>com.apple.security.network.client</key>
8+
<true/>
9+
</dict>
10+
</plist>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>NSExtension</key>
6+
<dict>
7+
<key>NSExtensionPointIdentifier</key>
8+
<string>com.apple.widgetkit-extension</string>
9+
</dict>
10+
</dict>
11+
</plist>

0 commit comments

Comments
 (0)