Skip to content

Commit ffa070f

Browse files
cbaker6TomWFox
andauthored
Support for PushNotifications (#78)
* Support for PushNotifications * Update docs * Apply suggestions from code review Co-authored-by: Tom Fox <[email protected]> * Compiler check and enable codecov on Swift 5.2 Co-authored-by: Tom Fox <[email protected]>
1 parent 7a282e1 commit ffa070f

File tree

8 files changed

+112
-13
lines changed

8 files changed

+112
-13
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ jobs:
8686
run: swift test --enable-code-coverage -v
8787
env:
8888
DEVELOPER_DIR: ${{ env.CI_XCODE_VER }}
89+
- name: Prepare codecov
90+
run: xcrun llvm-cov export -format="lcov" .build/debug/ParseSwiftPackageTests.xctest/Contents/MacOS/ParseSwiftPackageTests -instr-profile .build/debug/codecov/default.profdata > info.lcov
91+
env:
92+
DEVELOPER_DIR: ${{ env.CI_XCODE_VER }}
93+
- name: Send codecov
94+
run: bash <(curl https://codecov.io/bash)
8995

9096
linux:
9197
runs-on: ubuntu-18.04

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
# Parse-Swift Changelog
22

33
### main
4-
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.3...main)
4+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.4...main)
55
* _Contributing to this repo? Add info about your change here to be included in next release_
66

7+
### 1.1.4
8+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.3...1.1.4)
9+
10+
__New features__
11+
- Support for push notifications through `ParseInstallation` ([#78](https://github.com/parse-community/Parse-Swift/pull/78)), thanks to [Corey Baker](https://github.com/cbaker6).
12+
- Fetch with include ([#74](https://github.com/parse-community/Parse-Swift/pull/74)), thanks to [Corey Baker](https://github.com/cbaker6).
13+
14+
__Improvements__
15+
- Added `ParseLiveQuery` SwiftUI example to Playgrounds ([#77](https://github.com/parse-community/Parse-Swift/pull/77)), thanks to [Corey Baker](https://github.com/cbaker6).
16+
717
### 1.1.3
818
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.2...1.1.3)
919

ParseSwift.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "ParseSwift"
3-
s.version = "1.1.3"
3+
s.version = "1.1.4"
44
s.summary = "Parse Pure Swift SDK"
55
s.homepage = "https://github.com/parse-community/Parse-Swift"
66
s.authors = {

ParseSwift.xcodeproj/project.pbxproj

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@
9595
7033ECB825584A83009770F3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7033ECB625584A83009770F3 /* Main.storyboard */; };
9696
7033ECBA25584A85009770F3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7033ECB925584A85009770F3 /* Assets.xcassets */; };
9797
7033ECBD25584A85009770F3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7033ECBB25584A85009770F3 /* LaunchScreen.storyboard */; };
98+
70386A0625D9718C0048EC1B /* Data+hexString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A0525D9718C0048EC1B /* Data+hexString.swift */; };
99+
70386A0725D9718C0048EC1B /* Data+hexString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A0525D9718C0048EC1B /* Data+hexString.swift */; };
100+
70386A0825D9718C0048EC1B /* Data+hexString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A0525D9718C0048EC1B /* Data+hexString.swift */; };
101+
70386A0925D9718C0048EC1B /* Data+hexString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A0525D9718C0048EC1B /* Data+hexString.swift */; };
98102
7044C17525C4ECFF0011F6E7 /* ParseCloud+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C17425C4ECFF0011F6E7 /* ParseCloud+combine.swift */; };
99103
7044C17625C4ECFF0011F6E7 /* ParseCloud+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C17425C4ECFF0011F6E7 /* ParseCloud+combine.swift */; };
100104
7044C17725C4ECFF0011F6E7 /* ParseCloud+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C17425C4ECFF0011F6E7 /* ParseCloud+combine.swift */; };
@@ -536,6 +540,7 @@
536540
7033ECB925584A85009770F3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
537541
7033ECBC25584A85009770F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
538542
7033ECBE25584A85009770F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
543+
70386A0525D9718C0048EC1B /* Data+hexString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+hexString.swift"; sourceTree = "<group>"; };
539544
7044C17425C4ECFF0011F6E7 /* ParseCloud+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseCloud+combine.swift"; sourceTree = "<group>"; };
540545
7044C18225C4EFC10011F6E7 /* ParseConfig+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseConfig+combine.swift"; sourceTree = "<group>"; };
541546
7044C19025C4F5B60011F6E7 /* ParseFile+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseFile+combine.swift"; sourceTree = "<group>"; };
@@ -884,6 +889,7 @@
884889
70110D562506CE890091CC1D /* BaseParseInstallation.swift */,
885890
F97B45C224D9C6F200F4A88B /* NoBody.swift */,
886891
70D1BE7225BB43EB00A42E7C /* BaseConfig.swift */,
892+
70386A0525D9718C0048EC1B /* Data+hexString.swift */,
887893
);
888894
path = Internal;
889895
sourceTree = "<group>";
@@ -1520,6 +1526,7 @@
15201526
7044C1C825C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */,
15211527
707A3BF125B0A4F0000D215C /* ParseAuthentication.swift in Sources */,
15221528
70D1BE7325BB43EB00A42E7C /* BaseConfig.swift in Sources */,
1529+
70386A0625D9718C0048EC1B /* Data+hexString.swift in Sources */,
15231530
F97B465F24D9C7B500F4A88B /* KeychainStore.swift in Sources */,
15241531
705726E02592C2A800F0ADD5 /* ParseHash.swift in Sources */,
15251532
70110D52250680140091CC1D /* ParseConstants.swift in Sources */,
@@ -1651,6 +1658,7 @@
16511658
7044C1C925C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */,
16521659
707A3BF225B0A4F0000D215C /* ParseAuthentication.swift in Sources */,
16531660
70D1BE7425BB43EB00A42E7C /* BaseConfig.swift in Sources */,
1661+
70386A0725D9718C0048EC1B /* Data+hexString.swift in Sources */,
16541662
F97B466024D9C7B500F4A88B /* KeychainStore.swift in Sources */,
16551663
705726E12592C2A800F0ADD5 /* ParseHash.swift in Sources */,
16561664
70110D53250680140091CC1D /* ParseConstants.swift in Sources */,
@@ -1838,6 +1846,7 @@
18381846
7044C1CB25C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */,
18391847
707A3BF425B0A4F0000D215C /* ParseAuthentication.swift in Sources */,
18401848
70D1BE7625BB43EB00A42E7C /* BaseConfig.swift in Sources */,
1849+
70386A0925D9718C0048EC1B /* Data+hexString.swift in Sources */,
18411850
F97B460524D9C6F200F4A88B /* NoBody.swift in Sources */,
18421851
705726E32592C2A800F0ADD5 /* ParseHash.swift in Sources */,
18431852
F97B45E124D9C6F200F4A88B /* AnyCodable.swift in Sources */,
@@ -1922,6 +1931,7 @@
19221931
7044C1CA25C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */,
19231932
707A3BF325B0A4F0000D215C /* ParseAuthentication.swift in Sources */,
19241933
70D1BE7525BB43EB00A42E7C /* BaseConfig.swift in Sources */,
1934+
70386A0825D9718C0048EC1B /* Data+hexString.swift in Sources */,
19251935
F97B460424D9C6F200F4A88B /* NoBody.swift in Sources */,
19261936
705726E22592C2A800F0ADD5 /* ParseHash.swift in Sources */,
19271937
F97B45E024D9C6F200F4A88B /* AnyCodable.swift in Sources */,
@@ -2225,7 +2235,7 @@
22252235
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
22262236
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
22272237
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2228-
MARKETING_VERSION = 1.1.3;
2238+
MARKETING_VERSION = 1.1.4;
22292239
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
22302240
PRODUCT_NAME = ParseSwift;
22312241
SKIP_INSTALL = YES;
@@ -2249,7 +2259,7 @@
22492259
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
22502260
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
22512261
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2252-
MARKETING_VERSION = 1.1.3;
2262+
MARKETING_VERSION = 1.1.4;
22532263
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
22542264
PRODUCT_NAME = ParseSwift;
22552265
SKIP_INSTALL = YES;
@@ -2315,7 +2325,7 @@
23152325
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
23162326
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
23172327
MACOSX_DEPLOYMENT_TARGET = 10.13;
2318-
MARKETING_VERSION = 1.1.3;
2328+
MARKETING_VERSION = 1.1.4;
23192329
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
23202330
PRODUCT_NAME = ParseSwift;
23212331
SDKROOT = macosx;
@@ -2341,7 +2351,7 @@
23412351
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
23422352
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
23432353
MACOSX_DEPLOYMENT_TARGET = 10.13;
2344-
MARKETING_VERSION = 1.1.3;
2354+
MARKETING_VERSION = 1.1.4;
23452355
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
23462356
PRODUCT_NAME = ParseSwift;
23472357
SDKROOT = macosx;
@@ -2488,7 +2498,7 @@
24882498
INFOPLIST_FILE = "ParseSwift-watchOS/Info.plist";
24892499
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
24902500
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2491-
MARKETING_VERSION = 1.1.3;
2501+
MARKETING_VERSION = 1.1.4;
24922502
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
24932503
MTL_FAST_MATH = YES;
24942504
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-watchOS";
@@ -2517,7 +2527,7 @@
25172527
INFOPLIST_FILE = "ParseSwift-watchOS/Info.plist";
25182528
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
25192529
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2520-
MARKETING_VERSION = 1.1.3;
2530+
MARKETING_VERSION = 1.1.4;
25212531
MTL_FAST_MATH = YES;
25222532
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-watchOS";
25232533
PRODUCT_NAME = ParseSwift;
@@ -2544,7 +2554,7 @@
25442554
INFOPLIST_FILE = "ParseSwift-tvOS/Info.plist";
25452555
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
25462556
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2547-
MARKETING_VERSION = 1.1.3;
2557+
MARKETING_VERSION = 1.1.4;
25482558
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
25492559
MTL_FAST_MATH = YES;
25502560
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-tvOS";
@@ -2572,7 +2582,7 @@
25722582
INFOPLIST_FILE = "ParseSwift-tvOS/Info.plist";
25732583
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
25742584
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
2575-
MARKETING_VERSION = 1.1.3;
2585+
MARKETING_VERSION = 1.1.4;
25762586
MTL_FAST_MATH = YES;
25772587
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-tvOS";
25782588
PRODUCT_NAME = ParseSwift;

Scripts/jazzy.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ bundle exec jazzy \
55
--author_url http://parseplatform.org \
66
--github_url https://github.com/parse-community/Parse-Swift \
77
--root-url http://parseplatform.org/Parse-Swift/api/ \
8-
--module-version 1.1.3 \
8+
--module-version 1.1.4 \
99
--theme fullwidth \
1010
--skip-undocumented \
1111
--output ./docs/api \
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// Data+hexString.swift
3+
// ParseSwift
4+
//
5+
// Created by Corey Baker on 2/14/21.
6+
// Copyright © 2021 Parse Community. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
// Credit to: https://stackoverflow.com/questions/39075043/how-to-convert-data-to-hex-string-in-swift
12+
internal extension Data {
13+
struct HexEncodingOptions: OptionSet {
14+
let rawValue: Int
15+
static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
16+
}
17+
18+
func hexEncodedString(options: HexEncodingOptions = []) -> String {
19+
let hexDigits = options.contains(.upperCase) ? "0123456789ABCDEF" : "0123456789abcdef"
20+
#if compiler(>=5.3)
21+
if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
22+
let utf8Digits = Array(hexDigits.utf8)
23+
return String(unsafeUninitializedCapacity: 2 * count) { (ptr) -> Int in
24+
var mutablePtr = ptr.baseAddress!
25+
for byte in self {
26+
mutablePtr[0] = utf8Digits[Int(byte / 16)]
27+
mutablePtr[1] = utf8Digits[Int(byte % 16)]
28+
mutablePtr += 2
29+
}
30+
return 2 * count
31+
}
32+
} else {
33+
let utf16Digits = Array(hexDigits.utf16)
34+
var chars: [unichar] = []
35+
chars.reserveCapacity(2 * count)
36+
for byte in self {
37+
chars.append(utf16Digits[Int(byte / 16)])
38+
chars.append(utf16Digits[Int(byte % 16)])
39+
}
40+
return String(utf16CodeUnits: chars, count: chars.count)
41+
}
42+
#else
43+
let utf16Digits = Array(hexDigits.utf16)
44+
var chars: [unichar] = []
45+
chars.reserveCapacity(2 * count)
46+
for byte in self {
47+
chars.append(utf16Digits[Int(byte / 16)])
48+
chars.append(utf16Digits[Int(byte % 16)])
49+
}
50+
return String(utf16CodeUnits: chars, count: chars.count)
51+
#endif
52+
}
53+
}

Sources/ParseSwift/Objects/ParseInstallation.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ import AppKit
2828
when the `ParseInstallation` is saved, thus these fields might not reflect the
2929
latest device state if the installation has not recently been saved.
3030

31-
`ParseInstallation` installations which have a valid `deviceToken` and are saved to
32-
the Parse cloud can be used to target push notifications.
31+
`ParseInstallation`s which have a valid `deviceToken` and are saved to
32+
the Parse Server can be used to target push notifications. Use `setDeviceToken` to set the
33+
`deviceToken` properly.
3334

3435
- warning: Only use `ParseInstallation.current` installations on the main thread as they
3536
require UIApplication for `badge`
@@ -95,6 +96,17 @@ extension ParseInstallation {
9596

9697
return .installations
9798
}
99+
100+
/**
101+
Sets the device token string property from an `Data`-encoded token.
102+
- parameter data: A token that identifies the device.
103+
*/
104+
mutating public func setDeviceToken(_ data: Data) {
105+
let deviceTokenString = data.hexEncodedString()
106+
if deviceToken != deviceTokenString {
107+
deviceToken = deviceTokenString
108+
}
109+
}
98110
}
99111

100112
// MARK: CurrentInstallationContainer

Tests/ParseSwiftTests/ParseInstallationTests.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l
155155
wait(for: [expectation1], timeout: 20.0)
156156
}
157157

158+
func testDeviceTokenAsString() throws {
159+
let data = Data([0, 1, 127, 128, 255])
160+
XCTAssertEqual(data.hexEncodedString(), "00017f80ff")
161+
XCTAssertEqual(data.hexEncodedString(options: .upperCase), "00017F80FF")
162+
}
163+
158164
func testInstallationMutableValuesCanBeChangedInMemory() {
159165
let expectation1 = XCTestExpectation(description: "Update installation1")
160166
DispatchQueue.main.async {
@@ -165,7 +171,9 @@ class ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_l
165171
}
166172

167173
Installation.current?.customKey = "Changed"
174+
Installation.current?.setDeviceToken(Data([0, 1, 127, 128, 255]))
168175
XCTAssertNotEqual(originalInstallation.customKey, Installation.current?.customKey)
176+
XCTAssertNotEqual(originalInstallation.deviceToken, Installation.current?.customKey)
169177
expectation1.fulfill()
170178
}
171179
wait(for: [expectation1], timeout: 20.0)

0 commit comments

Comments
 (0)