Skip to content

Commit

Permalink
Release 18.0.0 (#3037)
Browse files Browse the repository at this point in the history
* Release 18.0.0

* Add logging to contact

* Cleanup

* Tint refresh and sync ProgressViews with UIRefreshControl appearance

* Observer

---------

Co-authored-by: crow <david.crow@airship.com>
  • Loading branch information
rlepinski and crow committed Mar 21, 2024
1 parent 89b3601 commit 4296eef
Show file tree
Hide file tree
Showing 22 changed files with 202 additions and 1,538 deletions.
34 changes: 2 additions & 32 deletions Airship Sample/Airship Sample/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, DeepLinkDelegate,
forType: Activity<DeliveryAttributes>.self
)
}
}

if #available(iOS 17.2, *) {
LiveActivityUtils<DeliveryAttributes>.trackActivitiesOnPushToStartUpdates {
$0.orderNumber
Activity<DeliveryAttributes>.airshipWatchActivities { activity in
Airship.channel.trackLiveActivity(activity, name: activity.attributes.orderNumber)
}
}
#endif
Expand Down Expand Up @@ -121,31 +119,3 @@ class AppDelegate: UIResponder, UIApplicationDelegate, DeepLinkDelegate,
return true
}
}
#if canImport(ActivityKit)
@available(iOS 16.2, *)
struct LiveActivityUtils<T: ActivityAttributes> {
public static func trackActivities(
nameBlock: @escaping @Sendable (T) -> String?
) {
Activity<T>.activities.filter { activity in
activity.activityState == .active || activity.activityState == .stale
}.forEach { activity in
if let name = nameBlock(activity.attributes) {
Airship.channel.trackLiveActivity(activity, name: name)
}
}
}

@available(iOS 17.2, *)
public static func trackActivitiesOnPushToStartUpdates(
nameBlock: @escaping @Sendable (T) -> String?
) {
Task {
trackActivities(nameBlock: nameBlock)
for await update in Activity<T>.pushToStartTokenUpdates {
trackActivities(nameBlock: nameBlock)
}
}
}
}
#endif
2 changes: 1 addition & 1 deletion Airship.podspec
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
AIRSHIP_VERSION="18.0.0-rc"
AIRSHIP_VERSION="18.0.0"

Pod::Spec.new do |s|
s.version = AIRSHIP_VERSION
Expand Down
19 changes: 9 additions & 10 deletions Airship/Airship.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
60A5CC102B29B4100017EDB2 /* RegionEventTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60A5CC0F2B29B4100017EDB2 /* RegionEventTest.swift */; };
60C1DB0F2A8B743C00A1D3DA /* AirshipEmbeddedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0B2A8B743B00A1D3DA /* AirshipEmbeddedView.swift */; };
60C1DB102A8B743C00A1D3DA /* AirshipEmbeddedViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0C2A8B743B00A1D3DA /* AirshipEmbeddedViewManager.swift */; };
60C1DB112A8B743C00A1D3DA /* AirshipEmbeddedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedViewModel.swift */; };
60C1DB112A8B743C00A1D3DA /* AirshipEmbeddedObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedObserver.swift */; };
60C1DB122A8B743C00A1D3DA /* EmbeddedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0E2A8B743C00A1D3DA /* EmbeddedView.swift */; };
60D1D9B82B68FB6400EBE0A4 /* PreparedTrigger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60D1D9B72B68FB6400EBE0A4 /* PreparedTrigger.swift */; };
60D1D9BB2B6A53F000EBE0A4 /* PreparedTriggerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60D1D9BA2B6A53F000EBE0A4 /* PreparedTriggerTest.swift */; };
Expand All @@ -191,7 +191,7 @@
60E09FDB2B2780DB005A16EA /* JsonMatcherTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60E09FDA2B2780DB005A16EA /* JsonMatcherTest.swift */; };
60E7DDAC2ABC4CF500072FA0 /* AirshipEmbeddedViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0C2A8B743B00A1D3DA /* AirshipEmbeddedViewManager.swift */; };
60E7DDAE2ABC4D1600072FA0 /* EmbeddedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0E2A8B743C00A1D3DA /* EmbeddedView.swift */; };
60E7DDAF2ABC4D1D00072FA0 /* AirshipEmbeddedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedViewModel.swift */; };
60E7DDAF2ABC4D1D00072FA0 /* AirshipEmbeddedObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedObserver.swift */; };
60E7DDB02ABC4D2100072FA0 /* AirshipEmbeddedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0B2A8B743B00A1D3DA /* AirshipEmbeddedView.swift */; };
60EACF542B7BF2EA00CAFDBB /* AirshipApptimizeIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60EACF532B7BF2EA00CAFDBB /* AirshipApptimizeIntegration.swift */; };
60EACFBF2B7D272000CAFDBB /* AirshipApptimizeIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60EACF532B7BF2EA00CAFDBB /* AirshipApptimizeIntegration.swift */; };
Expand Down Expand Up @@ -995,7 +995,7 @@
6EC367072AD8A8A400355D11 /* EmbeddedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0E2A8B743C00A1D3DA /* EmbeddedView.swift */; };
6EC367092AD8A8A400355D11 /* AirshipEmbeddedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0B2A8B743B00A1D3DA /* AirshipEmbeddedView.swift */; };
6EC3670A2AD8A8A400355D11 /* AirshipEmbeddedViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0C2A8B743B00A1D3DA /* AirshipEmbeddedViewManager.swift */; };
6EC3670B2AD8A8A400355D11 /* AirshipEmbeddedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedViewModel.swift */; };
6EC3670B2AD8A8A400355D11 /* AirshipEmbeddedObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedObserver.swift */; };
6EC755992A4E115400851ABB /* DeviceAudienceSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EC755982A4E115400851ABB /* DeviceAudienceSelector.swift */; };
6EC7559B2A4E129000851ABB /* DeviceTagSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EC7559A2A4E129000851ABB /* DeviceTagSelector.swift */; };
6EC7559F2A4E5AB200851ABB /* DeviceAudienceChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EC7559E2A4E5AB200851ABB /* DeviceAudienceChecker.swift */; };
Expand Down Expand Up @@ -1999,7 +1999,7 @@
60A5CC0F2B29B4100017EDB2 /* RegionEventTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionEventTest.swift; sourceTree = "<group>"; };
60C1DB0B2A8B743B00A1D3DA /* AirshipEmbeddedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AirshipEmbeddedView.swift; sourceTree = "<group>"; };
60C1DB0C2A8B743B00A1D3DA /* AirshipEmbeddedViewManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AirshipEmbeddedViewManager.swift; sourceTree = "<group>"; };
60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AirshipEmbeddedViewModel.swift; sourceTree = "<group>"; };
60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AirshipEmbeddedObserver.swift; sourceTree = "<group>"; };
60C1DB0E2A8B743C00A1D3DA /* EmbeddedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmbeddedView.swift; sourceTree = "<group>"; };
60D1D9B72B68FB6400EBE0A4 /* PreparedTrigger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreparedTrigger.swift; sourceTree = "<group>"; };
60D1D9BA2B6A53F000EBE0A4 /* PreparedTriggerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreparedTriggerTest.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3235,7 +3235,7 @@
children = (
60C1DB0B2A8B743B00A1D3DA /* AirshipEmbeddedView.swift */,
60C1DB0C2A8B743B00A1D3DA /* AirshipEmbeddedViewManager.swift */,
60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedViewModel.swift */,
60C1DB0D2A8B743B00A1D3DA /* AirshipEmbeddedObserver.swift */,
60C1DB0E2A8B743C00A1D3DA /* EmbeddedView.swift */,
6E40868B2B8931C900435E2C /* AirshipViewSizeReader.swift */,
6E40868D2B8D036600435E2C /* AirshipEmbeddedSize.swift */,
Expand Down Expand Up @@ -6162,7 +6162,7 @@
6EE49BE12A0AADC900AB1CF4 /* AppRemoteDataProviderDelegate.swift in Sources */,
C00ED4CF26C729390040C5D0 /* URLAllowList.swift in Sources */,
6E6BD24A2AEAFEB700B9DFC9 /* AirsihpTriggerContext.swift in Sources */,
60C1DB112A8B743C00A1D3DA /* AirshipEmbeddedViewModel.swift in Sources */,
60C1DB112A8B743C00A1D3DA /* AirshipEmbeddedObserver.swift in Sources */,
6E5A64D42AABBED600574085 /* MeteredUsageStore.swift in Sources */,
6E07689229FB39440014E2A9 /* AirshipUnsafeSendableWrapper.swift in Sources */,
6E6ED1492683D8E200A2CBD0 /* LocaleManager.swift in Sources */,
Expand Down Expand Up @@ -6792,7 +6792,7 @@
A6722A0D281A9E820033F54D /* AirshipPrivacyManager.swift in Sources */,
6E5A64D22AABBEAF00574085 /* AirshipMeteredUsageEvent.swift in Sources */,
6EE49C242A13E32B00AB1CF4 /* RemoteDataProviderProtocol.swift in Sources */,
6EC3670B2AD8A8A400355D11 /* AirshipEmbeddedViewModel.swift in Sources */,
6EC3670B2AD8A8A400355D11 /* AirshipEmbeddedObserver.swift in Sources */,
6ECDDE7629B80462009D79DB /* ChannelAuthTokenProvider.swift in Sources */,
6E5A64DB2AABC5A400574085 /* UAMeteredUsage.xcdatamodeld in Sources */,
6EC367072AD8A8A400355D11 /* EmbeddedView.swift in Sources */,
Expand Down Expand Up @@ -7105,7 +7105,7 @@
6E664BA826C4417400A2C8E5 /* ShareAction.swift in Sources */,
6E712BDA29CCD7BA0012FE27 /* ContactManager.swift in Sources */,
6E87BD6526D594870005D20D /* ChannelRegistrationPayload.swift in Sources */,
60E7DDAF2ABC4D1D00072FA0 /* AirshipEmbeddedViewModel.swift in Sources */,
60E7DDAF2ABC4D1D00072FA0 /* AirshipEmbeddedObserver.swift in Sources */,
6E91E45928EF423400B6F25E /* AirshipWorkResult.swift in Sources */,
6E692B0929E0DA5200D96CCC /* JavaScriptCommandDelegate.swift in Sources */,
6E95292D268B98A200398B54 /* MediaEventTemplate.swift in Sources */,
Expand Down Expand Up @@ -9190,8 +9190,7 @@
6E1CBE2C2BAA2AEA00519D9C /* AirshipAutomation.xcdatamodel */,
);
currentVersion = 6E1CBE2B2BAA2AEA00519D9C /* AirshipAutomation 2.xcdatamodel */;
name = AirshipAutomation.xcdatamodeld;
path = "AirshipAutomation.xcdatamodeld";
path = AirshipAutomation.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,19 @@ actor AutomationEngine : AutomationEngineProtocol {

func cancelSchedulesWith(type: AutomationSchedule.ScheduleType) async throws {
AirshipLogger.debug("Cancelling schedules with type \(type)")

await self.startTask?.value

//we don't store schedule type as a separate field, but it's a part of airship json, so we
// can't utilize core data to filter out our results
let ids = try await self.schedules.compactMap { schedule in
switch schedule.data {
case .actions: return schedule.identifier
default: return nil
case .actions: return type == .actions ? schedule.identifier : nil
case .inAppMessage: return type == .inAppMessage ? schedule.identifier : nil
case .deferred: return type == .deferred ? schedule.identifier : nil
}
}

try await store.deleteSchedules(scheduleIDs: ids)
await self.triggersProcessor.cancel(scheduleIDs: ids)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import AirshipCore
#endif

public typealias MessageConvertor = @Sendable (LegacyInAppMessage) -> AutomationSchedule?
public typealias MessageExtender = @Sendable (InAppMessage) -> InAppMessage
public typealias ScheduleExtender = @Sendable (AutomationSchedule) -> AutomationSchedule
public typealias MessageExtender = @Sendable (inout InAppMessage) -> Void
public typealias ScheduleExtender = @Sendable (inout AutomationSchedule) -> Void

/// Legacy in-app messaging protocol
public protocol LegacyInAppMessagingProtocol: AnyObject, Sendable {
Expand Down Expand Up @@ -151,33 +151,33 @@ final class LegacyInAppMessaging: LegacyInAppMessagingProtocol, @unchecked Senda
actions: message.onClick
)

let inAppMessage = InAppMessage(
var inAppMessage = InAppMessage(
name: message.alert,
displayContent: .banner(displayContent),
source: .legacyPush,
extras: message.extra
)

let finalMessage = self.messageExtender?(inAppMessage) ?? inAppMessage
self.messageExtender?(&inAppMessage)

// In terms of the scheduled message model, displayASAP means using an active session trigger.
// Otherwise the closest analog to the v1 behavior is the foreground trigger.
let trigger = self.displayASAPEnabled ?
AutomationTrigger.activeSession(count: 1) :
AutomationTrigger.foreground(count: 1)

let schedule = AutomationSchedule(
var schedule = AutomationSchedule(
identifier: message.identifier,
data: .inAppMessage(finalMessage),
data: .inAppMessage(inAppMessage),
triggers: [trigger],
created: date.now,
lastUpdated: date.now,
end: message.expiry,
campaigns: message.campaigns,
messageType: message.messageType
)

return self.scheduleExtender?(schedule) ?? schedule
self.scheduleExtender?(&schedule)
return schedule
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ final class LegacyInAppMessagingTest: XCTestCase {

await MainActor.run { [messaging = self.subject!] in
messaging.messageExtender = { input in
return InAppMessage(name: extendedMessageName, displayContent: input.displayContent)
input.name = extendedMessageName
}
}

Expand Down Expand Up @@ -487,12 +487,11 @@ final class LegacyInAppMessagingTest: XCTestCase {
"alert": "test alert"
]
]

let extendedScheduleId = "extended schedule id"


await MainActor.run { [messaging = self.subject!] in
messaging.scheduleExtender = { input in
return AutomationSchedule(identifier: extendedScheduleId, triggers: input.triggers, data: input.data)
input.limit = 10
}
}

Expand All @@ -505,7 +504,7 @@ final class LegacyInAppMessagingTest: XCTestCase {
await fulfillment(of: [expection], timeout: 5)

let schedule = try await requireFirstSchedule()
XCTAssertEqual(extendedScheduleId, schedule.identifier)
XCTAssertEqual(10, schedule.limit)
}

func testReceiveRemoteIgnoresNonlegacyMessages() async throws {
Expand Down
2 changes: 1 addition & 1 deletion Airship/AirshipConfig.xcconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//* Copyright Airship and Contributors */

CURRENT_PROJECT_VERSION = 18.0.0-rc
CURRENT_PROJECT_VERSION = 18.0.0

// Uncomment to include the preview build warning
// OTHER_CFLAGS = $(inherited) -DUA_PREVIEW=1
5 changes: 5 additions & 0 deletions Airship/AirshipCore/Source/AirshipContact.swift
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ public final class AirshipContact: NSObject, AirshipContactProtocol, @unchecked
@objc
public func reset() {
guard self.privacyManager.isEnabled(.contacts) else {
AirshipLogger.trace("Contacts are disabled, ignoring reset request")
return
}
self.addOperation(.reset)
Expand All @@ -305,6 +306,7 @@ public final class AirshipContact: NSObject, AirshipContactProtocol, @unchecked
@objc
public func notifyRemoteLogin() {
guard self.privacyManager.isEnabled(.contacts) else {
AirshipLogger.trace("Contacts are disabled, ignoring notifyRemoteLogin request")
return
}
self.addOperation(.verify(self.date.now, required: true))
Expand All @@ -316,6 +318,7 @@ public final class AirshipContact: NSObject, AirshipContactProtocol, @unchecked
public func editTagGroups() -> TagGroupsEditor {
return TagGroupsEditor { updates in
guard !updates.isEmpty else {
AirshipLogger.trace("Empty tag group updates, ignoring")
return
}

Expand Down Expand Up @@ -347,6 +350,7 @@ public final class AirshipContact: NSObject, AirshipContactProtocol, @unchecked
public func editAttributes() -> AttributesEditor {
return AttributesEditor { updates in
guard !updates.isEmpty else {
AirshipLogger.trace("Empty attribute updates, ignoring")
return
}

Expand Down Expand Up @@ -634,6 +638,7 @@ public final class AirshipContact: NSObject, AirshipContactProtocol, @unchecked

private func addOperation(_ operation: ContactOperation) {
self.serialQueue.enqueue {
AirshipLogger.trace("Adding contact operation \(operation.type)")
await self.contactManager.addOperation(operation)
}
}
Expand Down
4 changes: 4 additions & 0 deletions Airship/AirshipCore/Source/AirshipSDKExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public enum AirshipSDKExtension: Int {
case reactNative = 4
/// The Titanium SDK extension.
case titanium = 5
/// The Capacitor SDK extension.
case capacitor = 6
}

extension AirshipSDKExtension {
Expand All @@ -35,6 +37,8 @@ extension AirshipSDKExtension {
return "react-native"
case .titanium:
return "titanium"
case .capacitor:
return "capacitor"
}
}
}
2 changes: 1 addition & 1 deletion Airship/AirshipCore/Source/AirshipVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import Foundation

public struct AirshipVersion {
public static let version = "18.0.0-rc"
public static let version = "18.0.0"
public static func get() -> String {
return version
}
Expand Down
30 changes: 22 additions & 8 deletions Airship/AirshipCore/Source/ContactManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,13 @@ actor ContactManager: ContactManagerProtocol {

// Worker -> one at a time
private func perfromNextOperation() async throws -> Bool {
guard self.isEnabled else { return true }
guard self.isEnabled else {
AirshipLogger.trace("Contact manager is not enabled, unable to perform operation")
return true
}

guard !self.operationEntries.isEmpty else {
AirshipLogger.trace("Operations are empty")
return true
}

Expand All @@ -256,6 +260,7 @@ actor ContactManager: ContactManagerProtocol {
yieldContactUpdates()

guard let operationGroup = prepareNextOperationGroup() else {
AirshipLogger.trace("Next operation group is nil")
return true
}

Expand Down Expand Up @@ -287,10 +292,13 @@ actor ContactManager: ContactManagerProtocol {
}

private func enqueueTask() {
guard
self.channel.identifier != nil,
self.isEnabled
else {
guard self.isEnabled else {
AirshipLogger.trace("Contact manager is not enabled, unable to enqueue task")
return
}

guard self.channel.identifier != nil else {
AirshipLogger.trace("Channel not created, unable to enqueue task")
return
}

Expand Down Expand Up @@ -323,7 +331,9 @@ actor ContactManager: ContactManagerProtocol {
}

private func performOperation(_ operation: ContactOperation) async throws -> Bool {
AirshipLogger.trace("Performing operation \(operation.type)")
guard !self.isSkippable(operation: operation) else {
AirshipLogger.trace("Operation skippable, finished operation \(operation.type)")
return true
}

Expand Down Expand Up @@ -778,7 +788,12 @@ actor ContactManager: ContactManagerProtocol {
operationType == .resolve {

self.operationEntries = self.operationEntries.filter { entry in
result.contact.channelAssociatedDate < entry.date
if (result.contact.channelAssociatedDate < entry.date) {
return true
} else {
AirshipLogger.trace("Dropping operation \(entry.operation.type) due to channel association date")
return false
}
}
}

Expand Down Expand Up @@ -830,8 +845,7 @@ actor ContactManager: ContactManagerProtocol {
channel: AssociatedChannel? = nil
) async {

guard let contactInfo = self.lastContactInfo,
contactInfo.contactID == contactID else {
guard let contactInfo = self.lastContactInfo, contactInfo.contactID == contactID else {
return
}

Expand Down

0 comments on commit 4296eef

Please sign in to comment.