Skip to content

Commit

Permalink
Remote Messaging Framework for macOS (#3031)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/72649045549333/1202913520695928/f

Description:
This change adjusts RMF implementation to updates in BSK that add support for RMF on macOS.
* RMF is now controlled by a feature flag, enabled by default on iOS.
* Remote messaging config matcher creation has been moved into a standalone provider class
  that is otherwise separated from the RMF client.
* RemoteMessagingClient now implements a protocol from BSK that provides implementation
  for fetching and processing the config. The API is not static and the instance of the client is owned
  by AppDelegate.
* RemoteMessagingStore and HomePageConfiguration were moved out of AppDependencyProvider
  to have better control over their instantiation time and to allow for dependency injection.
  • Loading branch information
ayoy authored Jul 9, 2024
1 parent 259cd88 commit a68d0f9
Show file tree
Hide file tree
Showing 19 changed files with 306 additions and 363 deletions.
1 change: 1 addition & 0 deletions Core/AppConfigurationURLProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct AppConfigurationURLProvider: ConfigurationURLProviding {
case .trackerDataSet: return URL.trackerDataSet
case .surrogates: return URL.surrogates
case .FBConfig: fatalError("This feature is not supported on iOS")
case .remoteMessagingConfig: return RemoteMessagingClient.Constants.endpoint
}
}

Expand Down
1 change: 1 addition & 0 deletions Core/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public extension Configuration {
case .surrogates: return "surrogates"
case .trackerDataSet: return "trackerDataSet"
case .FBConfig: return "FBConfig"
case .remoteMessagingConfig: return "remoteMessagingConfig"
}
}

Expand Down
10 changes: 5 additions & 5 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
373608932ABB432600629E7F /* FavoritesDisplayMode+UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373608912ABB430D00629E7F /* FavoritesDisplayMode+UserDefaults.swift */; };
37445F972A155F7C0029F789 /* SyncDataProviders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37445F962A155F7C0029F789 /* SyncDataProviders.swift */; };
3760DFED299315EF0045A446 /* Waitlist in Frameworks */ = {isa = PBXBuildFile; productRef = 3760DFEC299315EF0045A446 /* Waitlist */; };
3768D8472C2CC98C004120AE /* RemoteMessagingConfigMatcherProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3768D8462C2CC98C004120AE /* RemoteMessagingConfigMatcherProvider.swift */; };
377D80222AB48554002AF251 /* FavoritesDisplayModeSyncHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377D80212AB48554002AF251 /* FavoritesDisplayModeSyncHandler.swift */; };
379E877429E97C8D001C8BB0 /* BookmarksCleanupErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379E877329E97C8D001C8BB0 /* BookmarksCleanupErrorHandling.swift */; };
37A6A8FE2AFD0208008580A3 /* FaviconsFetcherOnboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A6A8FD2AFD0208008580A3 /* FaviconsFetcherOnboarding.swift */; };
Expand Down Expand Up @@ -217,7 +218,6 @@
4B6484F327FD1E350050A7A1 /* MenuControllerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6484E927FD1E340050A7A1 /* MenuControllerView.swift */; };
4B6ED9452B992FE4007F5CAA /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B6ED9442B992FE4007F5CAA /* vpn-dark-mode.json */; };
4B75EA9226A266CB00018634 /* PrintingUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B75EA9126A266CB00018634 /* PrintingUserScript.swift */; };
4B78074E2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B78074D2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift */; };
4B948E2629DCCDB9002531FA /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 4B948E2529DCCDB9002531FA /* Persistence */; };
4BB7CBB02AF59C310014A35F /* VPNWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB7CBAF2AF59C310014A35F /* VPNWidget.swift */; };
4BBBBA872B02E85400D965DA /* DesignResourcesKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4BBBBA862B02E85400D965DA /* DesignResourcesKit */; };
Expand Down Expand Up @@ -1305,6 +1305,7 @@
3736088F2ABB1E6C00629E7F /* FavoritesDisplayModeStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesDisplayModeStorage.swift; sourceTree = "<group>"; };
373608912ABB430D00629E7F /* FavoritesDisplayMode+UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FavoritesDisplayMode+UserDefaults.swift"; sourceTree = "<group>"; };
37445F962A155F7C0029F789 /* SyncDataProviders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncDataProviders.swift; sourceTree = "<group>"; };
3768D8462C2CC98C004120AE /* RemoteMessagingConfigMatcherProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteMessagingConfigMatcherProvider.swift; sourceTree = "<group>"; };
377D80212AB48554002AF251 /* FavoritesDisplayModeSyncHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesDisplayModeSyncHandler.swift; sourceTree = "<group>"; };
379E877329E97C8D001C8BB0 /* BookmarksCleanupErrorHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksCleanupErrorHandling.swift; sourceTree = "<group>"; };
37A6A8FD2AFD0208008580A3 /* FaviconsFetcherOnboarding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconsFetcherOnboarding.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1335,7 +1336,6 @@
4B6484E927FD1E340050A7A1 /* MenuControllerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuControllerView.swift; sourceTree = "<group>"; };
4B6ED9442B992FE4007F5CAA /* vpn-dark-mode.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "vpn-dark-mode.json"; sourceTree = "<group>"; };
4B75EA9126A266CB00018634 /* PrintingUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrintingUserScript.swift; sourceTree = "<group>"; };
4B78074D2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteMessagingSurveyURLBuilder.swift; sourceTree = "<group>"; };
4BB7CBAF2AF59C310014A35F /* VPNWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNWidget.swift; sourceTree = "<group>"; };
4BBBBA912B03291700D965DA /* VPNWaitlistUserText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNWaitlistUserText.swift; sourceTree = "<group>"; };
4BC21A2C272388BD00229F0E /* RunLoopExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunLoopExtensionTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3355,7 +3355,6 @@
isa = PBXGroup;
children = (
7BC5711F2BDBB877003B0CCE /* VPNActivationDateStore.swift */,
4B78074D2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift */,
BDFF031F2BA3D3AD00F324C9 /* Feature Visibility */,
);
name = VPN;
Expand Down Expand Up @@ -4421,6 +4420,7 @@
isa = PBXGroup;
children = (
C1B7B52128941F2A0098FD6A /* RemoteMessagingClient.swift */,
3768D8462C2CC98C004120AE /* RemoteMessagingConfigMatcherProvider.swift */,
3712091D2C21E390003ADF3D /* RemoteMessagingStoreErrorHandling.swift */,
);
name = RemoteMessaging;
Expand Down Expand Up @@ -6522,6 +6522,7 @@
B609D5522862EAFF0088CAC2 /* InlineWKDownloadDelegate.swift in Sources */,
BDFF03222BA3D8E200F324C9 /* NetworkProtectionFeatureVisibility.swift in Sources */,
B652DEFD287BE67400C12A9C /* UserScripts.swift in Sources */,
3768D8472C2CC98C004120AE /* RemoteMessagingConfigMatcherProvider.swift in Sources */,
1D200C992BA3176D00108701 /* SettingsOthersView.swift in Sources */,
31DD208427395A5A008FB313 /* VoiceSearchHelper.swift in Sources */,
9874F9EE2187AFCE00CAF33D /* Themable.swift in Sources */,
Expand Down Expand Up @@ -6576,7 +6577,6 @@
F1386BA41E6846C40062FC3C /* TabDelegate.swift in Sources */,
37CF91602BB4737300BADCAE /* CrashCollectionOnboarding.swift in Sources */,
C1B924B72ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift in Sources */,
4B78074E2B183A1F009DB2CF /* RemoteMessagingSurveyURLBuilder.swift in Sources */,
3132FA2A27A0788F00DD7A12 /* QuickLookPreviewHelper.swift in Sources */,
D670E5BB2BB6A75300941A42 /* SubscriptionNavigationCoordinator.swift in Sources */,
C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */,
Expand Down Expand Up @@ -9946,7 +9946,7 @@
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 167.0.1;
version = 169.0.0;
};
};
9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/DuckDuckGo/BrowserServicesKit",
"state" : {
"revision" : "0746af01b77d39a1e037bea93b46591534a13b5c",
"version" : "167.0.1"
"revision" : "bfabf4518a33eb2b4b11003a15633a24c28fa922",
"version" : "169.0.0"
}
},
{
"identity" : "content-scope-scripts",
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/content-scope-scripts",
"state" : {
"revision" : "7ac68ae3bc052fa59adbc1ba8fd5cb5849a6bc99",
"version" : "5.25.0"
"revision" : "9c65477457126ab7ad963a32b7f85ce08e6bd1a7",
"version" : "6.0.0"
}
},
{
Expand Down
32 changes: 23 additions & 9 deletions DuckDuckGo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import Crashes
import Configuration
import Networking
import DDGSync
import RemoteMessaging
import SyncDataProviders
import Subscription

Expand Down Expand Up @@ -79,6 +80,10 @@ import WebKit
private var showKeyboardIfSettingOn = true
private var lastBackgroundDate: Date?

private(set) var homePageConfiguration: HomePageConfiguration!

private(set) var remoteMessagingClient: RemoteMessagingClient!

private(set) var syncService: DDGSync!
private(set) var syncDataProviders: SyncDataProviders!
private var syncDidFinishCancellable: AnyCancellable?
Expand Down Expand Up @@ -278,6 +283,22 @@ import WebKit
})
}

remoteMessagingClient = RemoteMessagingClient(
bookmarksDatabase: bookmarksDatabase,
appSettings: AppDependencyProvider.shared.appSettings,
internalUserDecider: AppDependencyProvider.shared.internalUserDecider,
configurationStore: ConfigurationStore.shared,
database: Database.shared,
errorEvents: RemoteMessagingStoreErrorHandling(),
remoteMessagingAvailabilityProvider: PrivacyConfigurationRemoteMessagingAvailabilityProvider(
privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager
)
)
remoteMessagingClient.registerBackgroundRefreshTaskHandler()

homePageConfiguration = HomePageConfiguration(variantManager: AppDependencyProvider.shared.variantManager,
remoteMessagingClient: remoteMessagingClient)

let previewsSource = TabPreviewsSource()
let historyManager = makeHistoryManager(AppDependencyProvider.shared.appSettings,
AppDependencyProvider.shared.internalUserDecider,
Expand All @@ -287,6 +308,7 @@ import WebKit
let main = MainViewController(bookmarksDatabase: bookmarksDatabase,
bookmarksDatabaseCleaner: syncDataProviders.bookmarksAdapter.databaseCleaner,
historyManager: historyManager,
homePageConfiguration: homePageConfiguration,
syncService: syncService,
syncDataProviders: syncDataProviders,
appSettings: AppDependencyProvider.shared.appSettings,
Expand Down Expand Up @@ -318,11 +340,6 @@ import WebKit
// Having both in `didBecomeActive` can sometimes cause the exception when running on a physical device, so registration happens here.
AppConfigurationFetch.registerBackgroundRefreshTaskHandler()

RemoteMessagingClient.registerBackgroundRefreshTaskHandler(
bookmarksDatabase: bookmarksDatabase,
favoritesDisplayMode: AppDependencyProvider.shared.appSettings.favoritesDisplayMode
)

UNUserNotificationCenter.current().delegate = self

window?.windowScene?.screenshotService?.delegate = self
Expand Down Expand Up @@ -616,10 +633,7 @@ import WebKit

private func refreshRemoteMessages() {
Task {
try? await RemoteMessagingClient.fetchAndProcess(
bookmarksDatabase: self.bookmarksDatabase,
favoritesDisplayMode: AppDependencyProvider.shared.appSettings.favoritesDisplayMode
)
try? await remoteMessagingClient.fetchAndProcess(using: remoteMessagingClient.store)
}
}

Expand Down
9 changes: 0 additions & 9 deletions DuckDuckGo/AppDependencyProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ protocol DependencyProvider {
var variantManager: VariantManager { get }
var internalUserDecider: InternalUserDecider { get }
var featureFlagger: FeatureFlagger { get }
var remoteMessagingStore: RemoteMessagingStore { get }
var homePageConfiguration: HomePageConfiguration { get }
var storageCache: StorageCache { get }
var voiceSearchHelper: VoiceSearchHelperProtocol { get }
var downloadManager: DownloadManager { get }
Expand Down Expand Up @@ -64,13 +62,6 @@ class AppDependencyProvider: DependencyProvider {
let internalUserDecider: InternalUserDecider = ContentBlocking.shared.privacyConfigurationManager.internalUserDecider
let featureFlagger: FeatureFlagger

let remoteMessagingStore: RemoteMessagingStore = RemoteMessagingStore(
database: Database.shared,
errorEvents: RemoteMessagingStoreErrorHandling(),
log: .remoteMessaging
)
lazy var homePageConfiguration: HomePageConfiguration = HomePageConfiguration(variantManager: variantManager,
remoteMessagingStore: remoteMessagingStore)
let storageCache = StorageCache()
let voiceSearchHelper: VoiceSearchHelperProtocol = VoiceSearchHelper()
let downloadManager = DownloadManager()
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/ConfigurationDebugViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class ConfigurationDebugViewController: UITableViewController {
case surrogates
case trackerDataSet
case privacyConfiguration
case remoteMessagingConfig
case resetEtags = "Reset ETags"

var showDetail: Bool {
Expand Down
2 changes: 2 additions & 0 deletions DuckDuckGo/ConfigurationURLDebugViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ struct CustomConfigurationURLProvider: ConfigurationURLProviding {
var customTrackerDataSetURL: URL?
var customSurrogatesURL: URL?
var customFBConfigURL: URL?
var customRemoteMessagingConfigURL: URL?

let defaultProvider = AppConfigurationURLProvider()

Expand All @@ -194,6 +195,7 @@ struct CustomConfigurationURLProvider: ConfigurationURLProviding {
case .trackerDataSet: customURL = customTrackerDataSetURL
case .surrogates: customURL = customSurrogatesURL
case .FBConfig: customURL = nil
case .remoteMessagingConfig: customURL = customRemoteMessagingConfigURL
}
return customURL ?? defaultURL
}
Expand Down
5 changes: 2 additions & 3 deletions DuckDuckGo/HomeCollectionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@ class HomeCollectionView: UICollectionView {
static let topInset: CGFloat = 79
}

var homePageConfiguration: HomePageConfiguration!
private weak var controller: HomeViewController!

private(set) var renderers: HomeViewSectionRenderers!

private lazy var collectionViewReorderingGesture =
UILongPressGestureRecognizer(target: self, action: #selector(self.collectionViewReorderingGestureHandler(gesture:)))

private lazy var homePageConfiguration = AppDependencyProvider.shared.homePageConfiguration


private var topIndexPath: IndexPath? {
for section in 0..<renderers.numberOfSections(in: self) where numberOfItems(inSection: section) > 0 {
return IndexPath(row: 0, section: section)
Expand Down
15 changes: 7 additions & 8 deletions DuckDuckGo/HomePageConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,13 @@ final class HomePageConfiguration: HomePageMessagesConfiguration {
// MARK: - Messages

private var homeMessageStorage: HomeMessageStorage
private var remoteMessagingStore: RemoteMessagingStore
private var remoteMessagingClient: RemoteMessagingClient

var homeMessages: [HomeMessage] = []

init(variantManager: VariantManager? = nil,
remoteMessagingStore: RemoteMessagingStore = AppDependencyProvider.shared.remoteMessagingStore) {
init(variantManager: VariantManager? = nil, remoteMessagingClient: RemoteMessagingClient) {
homeMessageStorage = HomeMessageStorage(variantManager: variantManager)
self.remoteMessagingStore = remoteMessagingStore
self.remoteMessagingClient = remoteMessagingClient
homeMessages = buildHomeMessages()
}

Expand All @@ -75,7 +74,7 @@ final class HomePageConfiguration: HomePageMessagesConfiguration {
}

private func remoteMessageToShow() -> HomeMessage? {
guard let remoteMessageToPresent = remoteMessagingStore.fetchScheduledRemoteMessage() else { return nil }
guard let remoteMessageToPresent = remoteMessagingClient.store.fetchScheduledRemoteMessage() else { return nil }
os_log("Remote message to show: %s", log: .remoteMessaging, type: .info, remoteMessageToPresent.id)
return .remoteMessage(remoteMessage: remoteMessageToPresent)
}
Expand All @@ -84,7 +83,7 @@ final class HomePageConfiguration: HomePageMessagesConfiguration {
switch homeMessage {
case .remoteMessage(let remoteMessage):
os_log("Home message dismissed: %s", log: .remoteMessaging, type: .info, remoteMessage.id)
remoteMessagingStore.dismissRemoteMessage(withId: remoteMessage.id)
remoteMessagingClient.store.dismissRemoteMessage(withID: remoteMessage.id)

if let index = homeMessages.firstIndex(of: homeMessage) {
homeMessages.remove(at: index)
Expand All @@ -102,11 +101,11 @@ final class HomePageConfiguration: HomePageMessagesConfiguration {
Pixel.fire(pixel: .remoteMessageShown,
withAdditionalParameters: [PixelParameters.message: "\(remoteMessage.id)"])

if !remoteMessagingStore.hasShownRemoteMessage(withId: remoteMessage.id) {
if !remoteMessagingClient.store.hasShownRemoteMessage(withID: remoteMessage.id) {
os_log("Remote message shown for first time: %s", log: .remoteMessaging, type: .info, remoteMessage.id)
Pixel.fire(pixel: .remoteMessageShownUnique,
withAdditionalParameters: [PixelParameters.message: "\(remoteMessage.id)"])
remoteMessagingStore.updateRemoteMessage(withId: remoteMessage.id, asShown: true)
remoteMessagingClient.store.updateRemoteMessage(withID: remoteMessage.id, asShown: true)
}

default:
Expand Down
Loading

0 comments on commit a68d0f9

Please sign in to comment.