Skip to content

Commit 18ea29e

Browse files
authored
fix(PushNotifications): Checking if there is a Provisioning Profile with the APS Entitlement in order to determine the ChannelType (#2824)
1 parent a7bbd61 commit 18ea29e

File tree

4 files changed

+206
-1
lines changed

4 files changed

+206
-1
lines changed

AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public class AWSPinpointFactory {
2121
private init() {}
2222

2323
static var credentialsProvider = AWSAuthService().getCredentialsProvider()
24+
25+
static var provisioningProfileReader: ProvisioningProfileReader = .default
2426

2527
public static func sharedPinpoint(appId: String,
2628
region: String) throws -> AWSPinpointBehavior {
@@ -29,10 +31,18 @@ public class AWSPinpointFactory {
2931
return existingContext
3032
}
3133

32-
var isDebug = false
34+
var isDebug: Bool
35+
/// Check for the APS Environment entitlement in a provisioning profile first
36+
if let apsEnvironment = provisioningProfileReader.profile()?.apsEnvironment {
37+
isDebug = apsEnvironment == .development
38+
} else {
39+
/// Fallback to the DEBUG flag
3340
#if DEBUG
3441
isDebug = true
42+
#else
43+
isDebug = false
3544
#endif
45+
}
3646
let configuration = PinpointContextConfiguration(
3747
appId: appId,
3848
region: region,
@@ -45,3 +55,4 @@ public class AWSPinpointFactory {
4555
return pinpointContext
4656
}
4757
}
58+
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
10+
struct ProvisioningProfile {
11+
enum APSEnvironment: String {
12+
case development
13+
case production
14+
}
15+
16+
var apsEnvironment: APSEnvironment?
17+
}
18+
19+
protocol ProvisioningProfileReader {
20+
func profile() -> ProvisioningProfile?
21+
}
22+
23+
extension ProvisioningProfileReader where Self == DefaultProvisioningProfileReader {
24+
static var `default`: ProvisioningProfileReader {
25+
DefaultProvisioningProfileReader()
26+
}
27+
}
28+
29+
struct DefaultProvisioningProfileReader: ProvisioningProfileReader {
30+
private struct Keys {
31+
static let entitlements = "Entitlements"
32+
static var apsEnvironment: String {
33+
#if os(macOS)
34+
return "com.apple.developer.aps-environment"
35+
#else
36+
return "aps-environment"
37+
#endif
38+
}
39+
}
40+
41+
private let fileName = "embedded"
42+
private var fileExtension: String = {
43+
#if os(macOS)
44+
return "provisionprofile"
45+
#else
46+
return "mobileprovision"
47+
#endif
48+
}()
49+
50+
private var url: URL? {
51+
#if os(macOS)
52+
if let url = Bundle.main.url(forResource: fileName, withExtension: fileExtension) {
53+
return url
54+
}
55+
56+
guard let enumerator = FileManager.default.enumerator(
57+
at: Bundle.main.bundleURL,
58+
includingPropertiesForKeys: [.isRegularFileKey],
59+
options: [.skipsHiddenFiles, .skipsPackageDescendants]
60+
) else {
61+
return nil
62+
}
63+
64+
let provisioningFile = "\(fileName).\(fileExtension)"
65+
for case let url as URL in enumerator where provisioningFile == url.lastPathComponent {
66+
return url
67+
}
68+
69+
return nil
70+
#else
71+
return Bundle.main.url(forResource: fileName, withExtension: fileExtension)
72+
#endif
73+
}
74+
75+
private var contents: Data? {
76+
guard let url = url,
77+
let contents = try? String(contentsOf: url, encoding: .isoLatin1) else {
78+
return nil
79+
}
80+
81+
let scanner = Scanner(string: contents)
82+
guard scanner.scanUpToString("<plist") != nil,
83+
let plist = scanner.scanUpToString("</plist>") else {
84+
return nil
85+
}
86+
87+
return "\(plist)</plist>".data(using: .isoLatin1)
88+
}
89+
90+
func profile() -> ProvisioningProfile? {
91+
guard let contents = contents,
92+
let provisioning = try? PropertyListSerialization.propertyList(
93+
from: contents,
94+
format: nil
95+
) as? [String: Any] else {
96+
return nil
97+
}
98+
99+
var profile = ProvisioningProfile()
100+
if let entitlements = provisioning[Keys.entitlements] as? [String: Any],
101+
let apnsEnvironment = entitlements[Keys.apsEnvironment] as? String {
102+
profile.apsEnvironment = ProvisioningProfile.APSEnvironment(rawValue: apnsEnvironment)
103+
}
104+
105+
return profile
106+
}
107+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
@testable import AmplifyTestCommon
9+
@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint
10+
import XCTest
11+
12+
final class AWSPinpointFactoryTests: XCTestCase {
13+
private var appId: String {
14+
UUID().uuidString
15+
}
16+
private let region = "region"
17+
private var mockedProfileReader: MockProvisioningProfileReader!
18+
19+
override func setUp() {
20+
mockedProfileReader = MockProvisioningProfileReader()
21+
AWSPinpointFactory.provisioningProfileReader = mockedProfileReader
22+
AWSPinpointFactory.credentialsProvider = MockCredentialsProvider()
23+
}
24+
25+
/// - Given: There is a provisioning profile that set the APS entitlement to production
26+
/// - When: A Pinpoint Context is created
27+
/// - Then: The endpoint's isDebug flag should be set to false
28+
func testSharedPinpoint_withProvisioningProfile_andAPSProduction_shouldSetDebugToFalse() async throws {
29+
mockedProfileReader.mockedProfile = .init(
30+
apsEnvironment: .production
31+
)
32+
33+
let pinpoint = try AWSPinpointFactory.sharedPinpoint(appId: appId, region: region)
34+
let context = try XCTUnwrap(pinpoint as? PinpointContext)
35+
let endpoint = await context.endpointClient.currentEndpointProfile()
36+
XCTAssertFalse(endpoint.isDebug)
37+
}
38+
39+
/// - Given: There is a provisioning profile that set the APS entitlement to development
40+
/// - When: A Pinpoint Context is created
41+
/// - Then: The endpoint's isDebug flag should be set to true
42+
func testSharedPinpoint_withProvisioningProfile_andAPSDevelopment_shouldSetDebugToFalse() async throws {
43+
mockedProfileReader.mockedProfile = .init(
44+
apsEnvironment: .development
45+
)
46+
47+
let pinpoint = try AWSPinpointFactory.sharedPinpoint(appId: appId, region: region)
48+
let context = try XCTUnwrap(pinpoint as? PinpointContext)
49+
let endpoint = await context.endpointClient.currentEndpointProfile()
50+
XCTAssertTrue(endpoint.isDebug)
51+
}
52+
53+
/// - Given: There is no provisioning profile
54+
/// - When: A Pinpoint Context is created
55+
/// - Then: The endpoint's isDebug flag should be determined based on the presence of the DEBUG flag
56+
func testSharedPinpoint_withoutProvisioningProfile_shouldSetDebugAccodingToDEBUGFlag() async throws {
57+
mockedProfileReader.mockedProfile = nil
58+
var isDebug: Bool
59+
#if DEBUG
60+
isDebug = true
61+
#else
62+
isDebug = false
63+
#endif
64+
65+
let pinpoint = try AWSPinpointFactory.sharedPinpoint(appId: appId, region: region)
66+
let context = try XCTUnwrap(pinpoint as? PinpointContext)
67+
let endpoint = await context.endpointClient.currentEndpointProfile()
68+
XCTAssertEqual(endpoint.isDebug, isDebug)
69+
}
70+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Foundation
9+
@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint
10+
11+
class MockProvisioningProfileReader: ProvisioningProfileReader {
12+
var mockedProfile: ProvisioningProfile?
13+
14+
func profile() -> ProvisioningProfile? {
15+
return mockedProfile
16+
}
17+
}

0 commit comments

Comments
 (0)