Skip to content

Commit 8a5fe1a

Browse files
committed
fix: Apple push notificaiton not working for live activities
1 parent 3f02f59 commit 8a5fe1a

File tree

10 files changed

+394
-153
lines changed

10 files changed

+394
-153
lines changed

ParseSwift.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@
202202
70D41D6728B0235100613510 /* MigrateObjCSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6628B0235100613510 /* MigrateObjCSDKTests.swift */; };
203203
70D41D6B28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */; };
204204
70D41D8028B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };
205+
70DDD0752C99079500C92D34 /* ParsePushPayloadAppleLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DDD0742C99077D00C92D34 /* ParsePushPayloadAppleLiveActivity.swift */; };
206+
70DDD0772C990F6C00C92D34 /* ParsePushApplePayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DDD0762C990F5E00C92D34 /* ParsePushApplePayload.swift */; };
207+
70DDD0792C99535F00C92D34 /* ParsePushAppleNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DDD0782C99535200C92D34 /* ParsePushAppleNotification.swift */; };
208+
70DDD07B2C99F85D00C92D34 /* ParsePushNotificationBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DDD07A2C99F85600C92D34 /* ParsePushNotificationBody.swift */; };
205209
70DFEA8A2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */; };
206210
70E09E1C262F0634002DD451 /* ParsePointerCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E09E1B262F0634002DD451 /* ParsePointerCombineTests.swift */; };
207211
70E6B016286120E00043EC4A /* ParseHookFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B015286120E00043EC4A /* ParseHookFunctionTests.swift */; };
@@ -552,6 +556,10 @@
552556
70D41D6628B0235100613510 /* MigrateObjCSDKTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateObjCSDKTests.swift; sourceTree = "<group>"; };
553557
70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateObjCSDKCombineTests.swift; sourceTree = "<group>"; };
554558
70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseKeychainAccessGroup.swift; sourceTree = "<group>"; };
559+
70DDD0742C99077D00C92D34 /* ParsePushPayloadAppleLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushPayloadAppleLiveActivity.swift; sourceTree = "<group>"; };
560+
70DDD0762C990F5E00C92D34 /* ParsePushApplePayload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushApplePayload.swift; sourceTree = "<group>"; };
561+
70DDD0782C99535200C92D34 /* ParsePushAppleNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushAppleNotification.swift; sourceTree = "<group>"; };
562+
70DDD07A2C99F85600C92D34 /* ParsePushNotificationBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushNotificationBody.swift; sourceTree = "<group>"; };
555563
70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializeSDKTests.swift; sourceTree = "<group>"; };
556564
70E09E1B262F0634002DD451 /* ParsePointerCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePointerCombineTests.swift; sourceTree = "<group>"; };
557565
70E6B015286120E00043EC4A /* ParseHookFunctionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookFunctionTests.swift; sourceTree = "<group>"; };
@@ -949,6 +957,7 @@
949957
705025EA285153BC008D6624 /* ParsePushApplePayloadable.swift */,
950958
705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */,
951959
705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */,
960+
70DDD0762C990F5E00C92D34 /* ParsePushApplePayload.swift */,
952961
70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */,
953962
919823642B3A134000E9591A /* ParsePointerable.swift */,
954963
700A8A652B4CC1E40087ADBE /* ParsePointerable+async.swift */,
@@ -1045,8 +1054,10 @@
10451054
isa = PBXGroup;
10461055
children = (
10471056
705025D0284CFCDE008D6624 /* ParsePushAppleAlert.swift */,
1057+
70DDD0782C99535200C92D34 /* ParsePushAppleNotification.swift */,
10481058
705025DA284D0D56008D6624 /* ParsePushAppleSound.swift */,
10491059
705025D5284D0C1D008D6624 /* ParsePushPayloadApple.swift */,
1060+
70DDD0742C99077D00C92D34 /* ParsePushPayloadAppleLiveActivity.swift */,
10501061
);
10511062
path = Apple;
10521063
sourceTree = "<group>";
@@ -1254,6 +1265,7 @@
12541265
7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */,
12551266
91285B1B26990D7F0051B544 /* ParsePolygon.swift */,
12561267
705025BC284C610C008D6624 /* ParsePush.swift */,
1268+
70DDD07A2C99F85600C92D34 /* ParsePushNotificationBody.swift */,
12571269
705025C1284C7841008D6624 /* ParsePush+async.swift */,
12581270
705025C6284C7883008D6624 /* ParsePush+combine.swift */,
12591271
705025B22845C302008D6624 /* ParsePushStatus.swift */,
@@ -1534,6 +1546,7 @@
15341546
F97B465F24D9C7B500F4A88B /* KeychainStore.swift in Sources */,
15351547
70B4E0C12762F313004C9757 /* QueryWhere.swift in Sources */,
15361548
70170A442656B02D0070C905 /* ParseAnalytics.swift in Sources */,
1549+
70DDD0792C99535F00C92D34 /* ParsePushAppleNotification.swift in Sources */,
15371550
70110D52250680140091CC1D /* ParseConstants.swift in Sources */,
15381551
91B79AC326EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */,
15391552
708EF0BD28D5F4140052EF35 /* API+Command+async.swift in Sources */,
@@ -1567,6 +1580,7 @@
15671580
704E781C28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,
15681581
7045769826BD917500F86F71 /* Query+async.swift in Sources */,
15691582
703B094E26BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,
1583+
70DDD0752C99079500C92D34 /* ParsePushPayloadAppleLiveActivity.swift in Sources */,
15701584
70386A3825D998D90048EC1B /* ParseLDAP.swift in Sources */,
15711585
709A14A02839CABD00BF85E5 /* ParseCLP.swift in Sources */,
15721586
700A8A662B4CC1E40087ADBE /* ParsePointerable+async.swift in Sources */,
@@ -1642,6 +1656,7 @@
16421656
70C5509225B4A99100B5DBC2 /* ParseOperationAddRelation.swift in Sources */,
16431657
708D035225215F9B00646C70 /* Deletable.swift in Sources */,
16441658
F97B466424D9C88600F4A88B /* SecureStorable.swift in Sources */,
1659+
70DDD07B2C99F85D00C92D34 /* ParsePushNotificationBody.swift in Sources */,
16451660
7030E08B29BBBF790021970D /* ParseConfigCodable+async.swift in Sources */,
16461661
7004C22025B63C7A005E0AD9 /* ParseRelation.swift in Sources */,
16471662
7003959525A10DFC0052CB31 /* Messages.swift in Sources */,
@@ -1665,6 +1680,7 @@
16651680
700395D125A147BE0052CB31 /* QuerySubscribable.swift in Sources */,
16661681
70170A492656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */,
16671682
703B092B26BF290B005A112F /* ParseAuthentication+async.swift in Sources */,
1683+
70DDD0772C990F6C00C92D34 /* ParsePushApplePayload.swift in Sources */,
16681684
70CE0AB7285A83B100DAEA86 /* ParseHookable.swift in Sources */,
16691685
F97B45F624D9C6F200F4A88B /* ParseError.swift in Sources */,
16701686
7045769D26BD934000F86F71 /* ParseFile+async.swift in Sources */,
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//
2+
// ParsePushApplePayload.swift
3+
// ParseSwift
4+
//
5+
// Created by Corey Baker on 9/16/24.
6+
// Copyright © 2024 Network Reconnaissance Lab. All rights reserved.
7+
//
8+
9+
// swiftlint:disable line_length
10+
11+
protocol ParsePushApplePayload: ParsePushApplePayloadable {
12+
/**
13+
The background notification flag. If you are a writing an app using the Remote Notification
14+
Background Mode introduced in iOS7 (a.k.a. “Background Push”), set this value to
15+
1 to trigger a background update. For more informaiton, see [Apple's documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app).
16+
- warning: For Apple OS's only. You also have to set `pushType` starting iOS 13
17+
and watchOS 6.
18+
*/
19+
var contentAvailable: Int? { get set }
20+
/**
21+
The notification service app extension flag. Set this value to 1 to trigger the system to pass the notification to your notification service app extension before delivery. Use your extension to modify the notification’s content. For more informaiton, see [Apple's documentation](https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications).
22+
- warning: You also have to set `pushType` starting iOS 13
23+
and watchOS 6.
24+
*/
25+
var mutableContent: Int? { get set }
26+
/**
27+
The priority of the notification. Specify 10 to send the notification immediately.
28+
Specify 5 to send the notification based on power considerations on the user’s device.
29+
See Apple's [documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns)
30+
for more information.
31+
- warning: For Apple OS's only.
32+
*/
33+
var priority: Int? { get set }
34+
35+
var pushType: ParsePushPayloadApple.PushType? { get set }
36+
37+
var badge: AnyCodable? { get set }
38+
var sound: AnyCodable? { get set }
39+
}
40+
41+
extension ParsePushApplePayload {
42+
43+
/**
44+
Set the name of a sound file in your app’s main bundle or in the Library/Sounds folder
45+
of your app’s container directory. For information about how to prepare sounds, see
46+
[UNNotificationSound](https://developer.apple.com/documentation/usernotifications/unnotificationsound).
47+
- parameter sound: An instance of `ParsePushAppleSound`.
48+
- returns: A mutated instance of `ParsePushPayloadApple` for easy chaining.
49+
- warning: For Apple OS's only.
50+
*/
51+
public func setSound(_ sound: ParsePushAppleSound) -> Self {
52+
var mutablePayload = self
53+
mutablePayload.sound = AnyCodable(sound)
54+
return mutablePayload
55+
}
56+
57+
/**
58+
Set the name of a sound file in your app’s main bundle or in the Library/Sounds folder
59+
of your app’s container directory. Specify the string “default” to play the system
60+
sound. Pass a string for **regular** notifications. For critical alerts, pass the sound
61+
`ParsePushAppleSound` instead. For information about how to prepare sounds, see
62+
[UNNotificationSound](https://developer.apple.com/documentation/usernotifications/unnotificationsound).
63+
- parameter sound: A `String` or any `Codable` object that can be sent to APN.
64+
- returns: A mutated instance of `ParsePushPayloadApple` for easy chaining.
65+
- warning: For Apple OS's only.
66+
*/
67+
public func setSound<V>(_ sound: V) -> Self where V: Codable {
68+
var mutablePayload = self
69+
mutablePayload.sound = AnyCodable(sound)
70+
return mutablePayload
71+
}
72+
73+
/**
74+
Get the sound using any type that conforms to `Codable`.
75+
- returns: The sound casted to the inferred type.
76+
- throws: An error of type `ParseError`.
77+
*/
78+
public func getSound<V>() throws -> V where V: Codable {
79+
guard let sound = sound?.value as? V else {
80+
throw ParseError(code: .otherCause,
81+
message: "Cannot be casted to the inferred type")
82+
}
83+
return sound
84+
}
85+
86+
/**
87+
Set the badge to a specific value to display on your app's icon.
88+
- parameter badge: The number to display in a badge on your app’s icon.
89+
Specify 0 to remove the current badge, if any.
90+
- returns: A mutated instance of `ParsePushPayloadApple` for easy chaining.
91+
- warning: For Apple OS's only.
92+
*/
93+
public func setBadge(_ number: Int) -> Self {
94+
var mutablePayload = self
95+
mutablePayload.badge = AnyCodable(number)
96+
return mutablePayload
97+
}
98+
99+
/**
100+
Increment the badge value by 1 to display on your app's icon.
101+
- warning: For Apple OS's only.
102+
- returns: A mutated instance of `ParsePushPayloadApple` for easy chaining.
103+
*/
104+
public func incrementBadge() -> Self {
105+
var mutablePayload = self
106+
mutablePayload.badge = AnyCodable(ParseOperationIncrement(amount: 1))
107+
return mutablePayload
108+
}
109+
}

Sources/ParseSwift/Protocols/ParsePushApplePayloadable.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,44 @@ public protocol ParsePushApplePayloadable: ParsePushPayloadable {
8282
Specify for the `mdm` field where applicable.
8383
*/
8484
var mdm: String? { get set }
85+
86+
init()
87+
}
88+
89+
public extension ParsePushApplePayloadable {
90+
91+
/**
92+
The content of the alert message.
93+
*/
94+
var body: String? {
95+
get {
96+
alert?.body
97+
}
98+
set {
99+
if alert != nil {
100+
alert?.body = newValue
101+
} else if let newBody = newValue {
102+
alert = .init(body: newBody)
103+
}
104+
}
105+
}
106+
107+
/**
108+
Create an instance of `ParsePushPayloadApple` .
109+
- parameter alert: The alert payload for the Apple push notification.
110+
*/
111+
init(alert: ParsePushAppleAlert) {
112+
self.init()
113+
self.alert = alert
114+
}
115+
116+
/**
117+
Create an instance of `ParsePushPayloadApple` .
118+
- parameter body: The body message to display for the Apple push notification.
119+
*/
120+
init(body: String) {
121+
self.init()
122+
self.body = body
123+
}
124+
85125
}

Sources/ParseSwift/Types/ParsePush.swift

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@ public struct ParsePush<V: ParsePushPayloadable>: ParseTypeable {
3030
public var payload: V?
3131
/// When to send the notification.
3232
public var pushTime: Date?
33+
3334
/**
3435
The UNIX timestamp when the notification should expire.
3536
If the notification cannot be delivered to the device, will retry until it expires.
3637
An expiry of **0** indicates that the notification expires immediately, therefore
3738
no retries will be attempted.
3839
- note: This should not be set directly using a **Date** type. Instead it should
3940
be set using `expirationDate`.
40-
- warning: Cannot send a notification with this valuel and `expirationInterval` both set.
41+
- warning: Cannot send a notification with this value and `expirationInterval` both set.
4142
*/
4243
var expirationTime: TimeInterval?
4344

@@ -46,7 +47,7 @@ public struct ParsePush<V: ParsePushPayloadable>: ParseTypeable {
4647
If the notification cannot be delivered to the device, will retry until it expires.
4748
- note: This takes any date and turns it into a UNIX timestamp and sets the
4849
value of `expirationTime`.
49-
- warning: Cannot send a notification with this valuel and `expirationInterval` both set.
50+
- warning: Cannot send a notification with this value and `expirationInterval` both set.
5051
*/
5152
var expirationDate: Date? {
5253
get {
@@ -59,9 +60,10 @@ public struct ParsePush<V: ParsePushPayloadable>: ParseTypeable {
5960
expirationTime = newValue?.timeIntervalSince1970
6061
}
6162
}
63+
6264
/**
6365
The seconds from now to expire the notification.
64-
- warning: Cannot send a notification with this valuel and `expirationTime` both set.
66+
- warning: Cannot send a notification with this value and `expirationTime` both set.
6567
*/
6668
public var expirationInterval: Int?
6769

@@ -203,11 +205,13 @@ extension ParsePush {
203205
}
204206
}
205207

206-
func sendCommand() -> API.NonParseBodyCommand<Self, String> {
207-
208-
return API.NonParseBodyCommand(method: .POST,
209-
path: .push,
210-
body: self) { (data) -> String in
208+
func sendCommand() -> API.NonParseBodyCommand<ParsePushNotificationBody, String> {
209+
let body = ParsePushNotificationBody(push: self)
210+
let command = API.NonParseBodyCommand(
211+
method: .POST,
212+
path: .push,
213+
body: body
214+
) { (data) -> String in
211215
guard let response = try? ParseCoding.jsonDecoder().decode(PushResponse.self, from: data) else {
212216
throw ParseError(code: .otherCause,
213217
message: "The server is missing \"X-Parse-Push-Status-Id\" in its header response")
@@ -222,6 +226,7 @@ extension ParsePush {
222226
throw ParseError(code: .otherCause, message: "Push was unsuccessful")
223227
}
224228
}
229+
return command
225230
}
226231
}
227232

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//
2+
// ParsePushNotificationBody.swift
3+
// ParseSwift
4+
//
5+
// Created by Corey Baker on 9/17/24.
6+
// Copyright © 2024 Network Reconnaissance Lab. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
struct ParsePushNotificationBody: ParseTypeable {
12+
var `where`: QueryWhere?
13+
var channels: Set<String>?
14+
var data: AnyCodable?
15+
var pushTime: Date?
16+
var expirationTime: TimeInterval?
17+
var expirationInterval: Int?
18+
19+
enum CodingKeys: String, CodingKey {
20+
case pushTime = "push_time"
21+
case expirationTime = "expiration_time"
22+
case expirationInterval = "expiration_interval"
23+
case `where`, channels, data
24+
}
25+
26+
init<T: ParsePushApplePayload>(push: ParsePush<T>) {
27+
self.where = push.where
28+
self.channels = push.channels
29+
self.pushTime = push.pushTime
30+
self.expirationTime = push.expirationTime
31+
self.expirationInterval = push.expirationInterval
32+
if let payload = push.payload {
33+
self.data = AnyCodable(
34+
ParsePushAppleNotification(payload: payload)
35+
)
36+
}
37+
}
38+
39+
init<T: ParsePushPayloadable>(push: ParsePush<T>) {
40+
self.where = push.where
41+
self.channels = push.channels
42+
self.pushTime = push.pushTime
43+
self.expirationTime = push.expirationTime
44+
self.expirationInterval = push.expirationInterval
45+
if let payload = push.payload {
46+
self.data = AnyCodable(
47+
payload
48+
)
49+
}
50+
}
51+
}

Sources/ParseSwift/Types/ParsePushPayload/Apple/ParsePushAppleAlert.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Foundation
1515
for more information.
1616
*/
1717
public struct ParsePushAppleAlert: ParseTypeable {
18+
1819
/**
1920
The content of the alert message.
2021
*/
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// ParsePushAppleNotification.swift
3+
// ParseSwift
4+
//
5+
// Created by Corey Baker on 9/16/24.
6+
// Copyright © 2024 Network Reconnaissance Lab. All rights reserved.
7+
//
8+
9+
struct ParsePushAppleNotification<P: ParsePushApplePayload>: ParsePushPayloadable {
10+
11+
var aps: P?
12+
var collapseId: String?
13+
var pushType: ParsePushPayloadApple.PushType?
14+
var priority: Int?
15+
var mdm: String?
16+
public init() {}
17+
18+
public init(payload: P) {
19+
self.aps = payload
20+
self.collapseId = payload.collapseId
21+
self.pushType = payload.pushType
22+
self.priority = payload.priority
23+
self.mdm = payload.mdm
24+
}
25+
26+
enum CodingKeys: String, CodingKey {
27+
case pushType = "push_type"
28+
case collapseId = "collapse_id"
29+
case mdm = "_mdm"
30+
case aps, priority
31+
}
32+
33+
}

0 commit comments

Comments
 (0)