Skip to content
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

Push to start live activities #1377

Merged
merged 42 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
818f164
Live Activities Push To Start Initial Implementation
brismithers Feb 14, 2024
67c71f0
Minor cleanup / fixes
brismithers Feb 15, 2024
cc60218
* Fix issue where the dispatch queue wasn't being used on http reques…
brismithers Feb 15, 2024
f48a50c
Remove old live activities files
brismithers Feb 15, 2024
999fd40
* Add unit tests
brismithers Feb 22, 2024
742de58
* Change convenience method from `monitor` to `setup` and add setup o…
brismithers Feb 27, 2024
a293efc
Add more unit tests to LiveActivities
brismithers Feb 28, 2024
d558d6c
Add more unit tests to LiveActivities
brismithers Feb 28, 2024
b4b6d62
Fix rename of OneSignalCore->OneSignalCoreImpl after rebase
brismithers Mar 13, 2024
2f9ac14
Update for linter errors
brismithers Mar 13, 2024
68cf8fe
Minor refactoring and formatting cleanup
brismithers Mar 22, 2024
5601f1d
Fix issue with URL structure and activity type/id url encoding
brismithers Mar 22, 2024
51f8688
Update la request paths to not include `api/v1`
brismithers Mar 27, 2024
acf5a5a
Remove string variants of setPushToStartToken and removePushToStartToken
brismithers Mar 29, 2024
7a5e78e
Make example widgets more different from each other
brismithers Mar 29, 2024
91691fa
Do not embedd other frameworks in live activities framework
brismithers Mar 29, 2024
6378195
Remove old live activities groups from user framework
brismithers Mar 29, 2024
7eb4aa4
set build libraries for distribution to yes
emawby Mar 29, 2024
8e8a959
Change only_active_arch to NO for debug builds
emawby Mar 29, 2024
e8f31fb
Only include widgetextension in example app if not mac catalyst
emawby Mar 29, 2024
70fb392
Add ActivityKit dependency and remove Mac Catalyst target from OneSig…
emawby Mar 29, 2024
053416a
Only include OneSignalLiveActivities in OneSignalFramework if not mac…
emawby Mar 29, 2024
9b72b9a
Move OSLiveActivities to OSCore and create a stub in order to compile…
emawby Mar 29, 2024
6697850
Throw error when invalid activity type
brismithers Apr 2, 2024
486e6ca
Only invalidate request success cache when the subscription id changes
brismithers Apr 5, 2024
827523c
Merge branch 'main' into push-to-start-live-activities
brismithers Apr 9, 2024
6de5e3b
Add a OneSignalLiveActivities subspec
emawby Apr 9, 2024
b20838d
Mark the live activity framework as extension safe
emawby Apr 9, 2024
36b63eb
Update podspecs and build_all_frameworks to add OneSignalLiveActivities
emawby Apr 9, 2024
62b3017
Update Package.swift + script
nan-li Apr 11, 2024
45fedd4
Merge branch 'main' into push-to-start-live-activities
brismithers Apr 16, 2024
5311939
Push to start live activities default LA (#1416)
brismithers May 6, 2024
3ad6c3e
Merge branch 'main' into push-to-start-live-activities
brismithers May 6, 2024
b6488ba
Update config for OneSignalCoreMocks' XCTest dependency
nan-li May 6, 2024
cc06e25
[lint] run swiftlint --fix
nan-li May 6, 2024
98c38d5
[lint] disable cyclomatic_complexity for AnyCodable
nan-li May 6, 2024
7d681fc
[ci] update CI script to use xcode 15.2
nan-li May 7, 2024
005a8c1
* No longer pollPendingRequests when request fails prepareForExecution
brismithers May 7, 2024
4d8a28e
set shared client in testRequestWillNotExecuteWhenNoSubscription
brismithers May 7, 2024
7ec93f0
[`cd`] code sign the Live Activities framework
nan-li May 7, 2024
32b4840
Fix crash when starting live activity in example app
brismithers May 8, 2024
252c1c3
Add extra line to info.plist (removes bad compare)
brismithers May 8, 2024
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
1 change: 1 addition & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ jobs:
codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_Outcomes/OneSignalOutcomes.xcframework
codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_User/OneSignalUser.xcframework
codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_XCFramework/OneSignalFramework.xcframework
codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_LiveActivities/OneSignalLiveActivities.xcframework
shell: bash
- name: Update Swift Package
run: |
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ jobs:
runs-on: macos-latest-large

steps:
- name: Select Xcode Version
run: |
sudo xcode-select -s /Applications/Xcode_15.2.app
- name: Checkout OneSignal-iOS-SDK
uses: actions/checkout@v3
- name: Set Default Scheme
Expand Down
8 changes: 8 additions & 0 deletions OneSignal.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ Pod::Spec.new do |s|
ss.vendored_frameworks = 'iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework'
end

s.subspec 'OneSignalLiveActivities' do |ss|
ss.dependency 'OneSignal/OneSignalCore'
ss.dependency 'OneSignal/OneSignalOSCore'
ss.dependency 'OneSignal/OneSignalUser'
ss.vendored_frameworks = 'iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework'
end

s.subspec 'OneSignalLocation' do |ss|
ss.dependency 'OneSignal/OneSignalCore'
ss.dependency 'OneSignal/OneSignalOSCore'
Expand All @@ -70,6 +77,7 @@ Pod::Spec.new do |s|
ss.dependency 'OneSignal/OneSignalExtension'
ss.dependency 'OneSignal/OneSignalNotifications'
ss.dependency 'OneSignal/OneSignalUser'
ss.dependency 'OneSignal/OneSignalLiveActivities'
ss.ios.vendored_frameworks = 'iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework'
end

Expand Down
Empty file.
Empty file.
8 changes: 8 additions & 0 deletions OneSignalXCFramework.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ Pod::Spec.new do |s|
ss.vendored_frameworks = 'iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework'
end

s.subspec 'OneSignalLiveActivities' do |ss|
ss.dependency 'OneSignalXCFramework/OneSignalCore'
ss.dependency 'OneSignalXCFramework/OneSignalOSCore'
ss.dependency 'OneSignalXCFramework/OneSignalUser'
ss.vendored_frameworks = 'iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework'
end

s.subspec 'OneSignalLocation' do |ss|
ss.dependency 'OneSignalXCFramework/OneSignalCore'
ss.dependency 'OneSignalXCFramework/OneSignalOSCore'
Expand All @@ -70,6 +77,7 @@ Pod::Spec.new do |s|
ss.dependency 'OneSignalXCFramework/OneSignalExtension'
ss.dependency 'OneSignalXCFramework/OneSignalNotifications'
ss.dependency 'OneSignalXCFramework/OneSignalUser'
ss.dependency 'OneSignalXCFramework/OneSignalLiveActivities'
ss.ios.vendored_frameworks = 'iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework'
end

Expand Down
14 changes: 14 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ let package = Package(
"OneSignalFramework",
"OneSignalUser",
"OneSignalNotifications",
"OneSignalLiveActivities",
"OneSignalExtension",
"OneSignalOutcomes",
"OneSignalOSCore",
Expand Down Expand Up @@ -103,6 +104,14 @@ let package = Package(
],
path: "OneSignalOSCoreWrapper"
),
.target(
name: "OneSignalLiveActivitiesWrapper",
dependencies: [
"OneSignalUser",
"OneSignalCore"
],
path: "OneSignalLiveActivitiesWrapper"
),
.binaryTarget(
name: "OneSignalFramework",
url: "https://github.com/OneSignal/OneSignal-iOS-SDK/releases/download/5.1.6/OneSignalFramework.xcframework.zip",
Expand Down Expand Up @@ -147,6 +156,11 @@ let package = Package(
name: "OneSignalCore",
url: "https://github.com/OneSignal/OneSignal-iOS-SDK/releases/download/5.1.6/OneSignalCore.xcframework.zip",
checksum: "46be3f316ed4506ab88d787821476572c9b016d7778beaa60a59a607c6c223e7"
),
.binaryTarget(
name: "OneSignalLiveActivities",
url: "https://github.com/OneSignal/OneSignal-iOS-SDK/releases/download/5.1.0/OneSignalLiveActivities.xcframework.zip",
checksum: ""
)
]
)
1 change: 1 addition & 0 deletions default
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
UnitTestApp
9 changes: 9 additions & 0 deletions iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#import "AppDelegate.h"
#import "ViewController.h"
#import "OneSignalExample-Swift.h"

@interface OneSignalNotificationCenterDelegate: NSObject<UNUserNotificationCenterDelegate>
@end
Expand Down Expand Up @@ -74,6 +75,14 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(

NSLog(@"UNUserNotificationCenter.delegate: %@", UNUserNotificationCenter.currentNotificationCenter.delegate);

#if TARGET_OS_MACCATALYST
#else
if (@available(iOS 16.1, *)) {
[LiveActivityController start];
}
#endif


return YES;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* Modified MIT License
*
* Copyright 2023 OneSignal
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 1. The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 2. All copies of substantial portions of the Software may only be used in connection
* with services provided by OneSignal.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#if targetEnvironment(macCatalyst)
#else
import ActivityKit
import OneSignalLiveActivities

/**
An example of an ActivityAttribute that is "OneSignal SDK aware". This attribute conforms
to the OneSignalActivityAttributes protocol and has a onesignal property, which contains
metadata used by the OneSignal SDK. To enable this Live Activity type for OneSignal
you only need to call `enableLiveActivities`, the SDK takes care of the rest.
*/
struct ExampleAppFirstWidgetAttributes: OneSignalLiveActivityAttributes {
public struct ContentState: OneSignalLiveActivityContentState {
// Dynamic stateful properties about your activity go here!
var message: String

var onesignal: OneSignalLiveActivityContentStateData?
}

// Fixed non-changing properties about your activity go here!
var title: String

// OneSignal Attributes to allow the SDK to do it's thing
var onesignal: OneSignalLiveActivityAttributeData
}

/**
Another example of an ActivityAttribute that is "OneSignal SDK aware". A second attributes
structure is created here because the example app has two different "types" of Live Activity
experiences. Noting that `enableLiveActivities` must be called for each "type" of
Live Activity defined.
*/
struct ExampleAppSecondWidgetAttributes: OneSignalLiveActivityAttributes {
public struct ContentState: OneSignalLiveActivityContentState {
var message: String
var status: String
var progress: Double
var bugs: Int

var onesignal: OneSignalLiveActivityContentStateData?
}

// Fixed non-changing properties about your activity go here!
var title: String

// OneSignal Attributes to allow the SDK to do it's thing
var onesignal: OneSignalLiveActivityAttributeData
}

/**
This example of an ActivityAttribute is **not** "OneSignal SDK aware". Listening
to push to start tokens and update tokens for this activity must be done by the app
itself.
*/
struct ExampleAppThirdWidgetAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// Dynamic stateful properties about your activity go here!
var message: String
}

// Fixed non-changing properties about your activity go here!
var title: String

// Whether this LA was started via pushToStart (true), or via app (false)
var isPushToStart: Bool
}
#endif
115 changes: 95 additions & 20 deletions iOS_SDK/OneSignalDevApp/OneSignalDevApp/LiveActivityController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,43 +26,118 @@
*/

import Foundation
import ActivityKit
import UserNotifications
import OneSignalFramework
#if targetEnvironment(macCatalyst)
#else
import ActivityKit
import OneSignalLiveActivities
@objc
class LiveActivityController: NSObject {

@available(iOS 16.1, *)
@objc
static func start() {
// ExampleAppFirstWidgetAttributes and ExampleAppSecondWidgetAttributes enable the OneSignal SDK to
// listen for start/update tokens, this is the only call needed.
OneSignal.LiveActivities.setup(ExampleAppFirstWidgetAttributes.self)
OneSignal.LiveActivities.setup(ExampleAppSecondWidgetAttributes.self)

struct OneSignalWidgetAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// Dynamic stateful properties about your activity go here!
var message: String
// There is a "built in" Live Activity Widget Attributes called `DefaultLiveActivityAttributes`.
// This is mostly for cross-platform SDKs and allows OneSignal to handle everything but the
// creation of the Widget Extension.
OneSignal.LiveActivities.setupDefault()

if #available(iOS 17.2, *) {
// ExampleAppThirdWidgetAttributes is an example of how to manually set up LA.
// Setup an async task to monitor and send pushToStartToken updates to OneSignalSDK.
Task {
for try await data in Activity<ExampleAppThirdWidgetAttributes>.pushToStartTokenUpdates {
let token = data.map {String(format: "%02x", $0)}.joined()
OneSignal.LiveActivities.setPushToStartToken(ExampleAppThirdWidgetAttributes.self, withToken: token)
}
}
// Setup an async task to monitor for an activity to be started, for each started activity we
// can then set up an async task to monitor and send updateToken updates to OneSignalSDK. We
// filter out LA started in-app, because the `createActivity` function below does its own
// updateToken update monitoring. If there can be multiple instances of this activity-type,
// the activity-id (i.e. "my-activity-id") is most likely passed down as an attribute within
// ExampleAppThirdWidgetAttributes.
Task {
for await activity in Activity<ExampleAppThirdWidgetAttributes>.activityUpdates
where activity.attributes.isPushToStart {
Task {
for await pushToken in activity.pushTokenUpdates {
let token = pushToken.map {String(format: "%02x", $0)}.joined()
OneSignal.LiveActivities.enter("my-activity-id", withToken: token)
}
}
}
}
}
}

// Fixed non-changing properties about your activity go here!
var title: String
}
@objc
class LiveActivityController: NSObject {
// To aid in testing
static var counter = 0
/**
An example of starting a Live Activity whose attributes are "OneSignal SDK aware". The SDK will handle listening for update tokens on behalf of the app.
*/
static var counter1 = 0
@available(iOS 13.0, *)
@objc
static func createOneSignalAwareActivity(activityId: String) {
if #available(iOS 16.1, *) {
counter1 += 1
let oneSignalAttribute = OneSignalLiveActivityAttributeData.create(activityId: activityId)
let attributes = ExampleAppFirstWidgetAttributes(title: "#" + String(counter1) + " OneSignal Dev App Live Activity", onesignal: oneSignalAttribute)
let contentState = ExampleAppFirstWidgetAttributes.ContentState(message: "Update this message through push or with Activity Kit")
do {
_ = try Activity<ExampleAppFirstWidgetAttributes>.request(
attributes: attributes,
contentState: contentState,
pushType: .token)
} catch let error {
print(error.localizedDescription)
}
}
}

/**
An example of starting a Live Activity using the DefaultLiveActivityAttributes. The SDK will handle listening for update tokens on behalf of the app.
*/
@available(iOS 13.0, *)
@objc
static func createDefaultActivity(activityId: String) {
if #available(iOS 16.1, *) {
let attributeData: [String: Any] = ["title": "in-app-title"]
let contentData: [String: Any] = ["message": ["en": "HELLO", "es": "HOLA"], "progress": 0.58, "status": "1/15", "bugs": 2]

OneSignal.LiveActivities.startDefault(activityId, attributes: attributeData, content: contentData)
}
}

/**
An example of starting a Live Activity whose attributes are **not** "OneSignal SDK aware". The app must handle listening for update tokens and notify the OneSignal SDK.
*/
static var counter2 = 0
@available(iOS 13.0, *)
@objc
static func createActivity() async -> String? {
static func createActivity(activityId: String) async {
if #available(iOS 16.1, *) {
counter += 1
let attributes = OneSignalWidgetAttributes(title: "#" + String(counter) + " OneSignal Dev App Live Activity")
let contentState = OneSignalWidgetAttributes.ContentState(message: "Update this message through push or with Activity Kit")
counter2 += 1
let attributes = ExampleAppThirdWidgetAttributes(title: "#" + String(counter2) + " OneSignal Dev App Live Activity", isPushToStart: false)
let contentState = ExampleAppThirdWidgetAttributes.ContentState(message: "Update this message through push or with Activity Kit")
do {
let activity = try Activity<OneSignalWidgetAttributes>.request(
let activity = try Activity<ExampleAppThirdWidgetAttributes>.request(
attributes: attributes,
contentState: contentState,
pushType: .token)
for await data in activity.pushTokenUpdates {
let myToken = data.map {String(format: "%02x", $0)}.joined()
return myToken
OneSignal.LiveActivities.enter(activityId, withToken: myToken)
}
} catch let error {
print(error.localizedDescription)
return nil
}
}
return nil
}
}
#endif
10 changes: 5 additions & 5 deletions iOS_SDK/OneSignalDevApp/OneSignalDevApp/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -232,19 +232,19 @@ - (IBAction)sendUniqueOutcomeEvent:(id)sender {
}

- (IBAction)startAndEnterLiveActivity:(id)sender {
#if TARGET_OS_MACCATALYST
#else
if (@available(iOS 13.0, *)) {
NSString *activityId = [self.activityId text];
// Will not make a live activity if activityId is empty
if (activityId && activityId.length) {
[LiveActivityController createActivityWithCompletionHandler:^(NSString * token) {
if(token){
[OneSignal.LiveActivities enter:activityId withToken:token];
}
}];
// [LiveActivityController createDefaultActivityWithActivityId:activityId ];
[LiveActivityController createActivityWithActivityId:activityId completionHandler:nil ];
}
} else {
NSLog(@"Must use iOS 13 or later for swift concurrency which is required for [LiveActivityController createActivityWithCompletionHandler...");
}
#endif
}
- (IBAction)exitLiveActivity:(id)sender {
if (self.activityId.text && self.activityId.text.length) {
Expand Down
Loading
Loading