Skip to content

Commit

Permalink
Merge pull request #968 from cdhoffmann/migration
Browse files Browse the repository at this point in the history
[MOB-19513] Migration logic
  • Loading branch information
cdhoffmann authored Oct 2, 2023
2 parents 909434e + 135f157 commit b431e5a
Show file tree
Hide file tree
Showing 6 changed files with 796 additions and 4 deletions.
16 changes: 16 additions & 0 deletions AEPCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,11 @@
3FF829692509937100483C74 /* SignalIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FF829682509937100483C74 /* SignalIntegrationTests.swift */; };
3FF8296D2509942300483C74 /* rules_signal.json in Resources */ = {isa = PBXBuildFile; fileRef = 3FF8296B2509942300483C74 /* rules_signal.json */; };
752261862AA257F600D59847 /* FileSystemNamedCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 752261852AA257F600D59847 /* FileSystemNamedCollection.swift */; };
7522618B2AA929E300D59847 /* UserDefaultsMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7522618A2AA929E300D59847 /* UserDefaultsMigrator.swift */; };
7522618D2AABBE9600D59847 /* UserDefaultMigrationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7522618C2AABBE9600D59847 /* UserDefaultMigrationConstants.swift */; };
7522618F2AAF6E2400D59847 /* UserDefaultMigratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7522618E2AAF6E2400D59847 /* UserDefaultMigratorTests.swift */; };
753E9B432ABCDB1400A82A27 /* AEPLifecycle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FE6DDD124C62EE60065EA05 /* AEPLifecycle.framework */; };
753E9B442ABCDB7D00A82A27 /* AEPIdentity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FE6DE2F24C642330065EA05 /* AEPIdentity.framework */; };
75408CF72948EA0A00C44CE1 /* AtomicCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75408CF62948EA0A00C44CE1 /* AtomicCounterTests.swift */; };
75550A3F2A9930A500747BB7 /* NamedCollectionDataStoreFunctionalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75550A3E2A9930A500747BB7 /* NamedCollectionDataStoreFunctionalTests.swift */; };
75C0D9052A9D545100EF74BC /* DatastoreUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C0D9042A9D545100EF74BC /* DatastoreUtilities.swift */; };
Expand Down Expand Up @@ -1047,6 +1052,9 @@
5A089B5A7E9F846B8CB9EB34 /* Pods-AEPIntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AEPIntegrationTests.debug.xcconfig"; path = "Target Support Files/Pods-AEPIntegrationTests/Pods-AEPIntegrationTests.debug.xcconfig"; sourceTree = "<group>"; };
6D652C6627B749495CEE65C1 /* Pods-TestApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TestApp.debug.xcconfig"; path = "Target Support Files/Pods-TestApp/Pods-TestApp.debug.xcconfig"; sourceTree = "<group>"; };
752261852AA257F600D59847 /* FileSystemNamedCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileSystemNamedCollection.swift; sourceTree = "<group>"; };
7522618A2AA929E300D59847 /* UserDefaultsMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsMigrator.swift; sourceTree = "<group>"; };
7522618C2AABBE9600D59847 /* UserDefaultMigrationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultMigrationConstants.swift; sourceTree = "<group>"; };
7522618E2AAF6E2400D59847 /* UserDefaultMigratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultMigratorTests.swift; sourceTree = "<group>"; };
75408CF62948EA0A00C44CE1 /* AtomicCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicCounterTests.swift; sourceTree = "<group>"; };
75550A3E2A9930A500747BB7 /* NamedCollectionDataStoreFunctionalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NamedCollectionDataStoreFunctionalTests.swift; sourceTree = "<group>"; };
75C0D9042A9D545100EF74BC /* DatastoreUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatastoreUtilities.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1163,6 +1171,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
753E9B442ABCDB7D00A82A27 /* AEPIdentity.framework in Frameworks */,
753E9B432ABCDB1400A82A27 /* AEPLifecycle.framework in Frameworks */,
3FF8171C24D89B8F0064DFA1 /* AEPCoreMocks.framework in Frameworks */,
3FE6DDBC24C62DA80065EA05 /* AEPServicesMocks.framework in Frameworks */,
3F03984224BE65170019F095 /* AEPServices.framework in Frameworks */,
Expand Down Expand Up @@ -1277,6 +1287,8 @@
218C813D24EC4101009B4F31 /* V5MigrationConstants.swift */,
21F79AB624E704C5003204C3 /* IDParser.swift */,
21F79ABA24E70CDC003204C3 /* IDParsing.swift */,
7522618A2AA929E300D59847 /* UserDefaultsMigrator.swift */,
7522618C2AABBE9600D59847 /* UserDefaultMigrationConstants.swift */,
);
path = migration;
sourceTree = "<group>";
Expand Down Expand Up @@ -1342,6 +1354,7 @@
21F79ABD24E7144F003204C3 /* IDParserTests.swift */,
21F79AC024E72204003204C3 /* V4MigratorTests.swift */,
21CD581024EC7B8900D9D590 /* V5MigratorTests.swift */,
7522618E2AAF6E2400D59847 /* UserDefaultMigratorTests.swift */,
);
path = MigrationTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -3154,6 +3167,7 @@
3FB66AD524CA004400502CAF /* EventHubError.swift in Sources */,
24EDE33B26F39F450068A65F /* EventHistoryResult.swift in Sources */,
3FB66AD324CA004400502CAF /* ExtensionRuntime.swift in Sources */,
7522618B2AA929E300D59847 /* UserDefaultsMigrator.swift in Sources */,
3F2B1DA62631E7FE0030F50B /* RuleConsequence.swift in Sources */,
24EDE33326EFB7470068A65F /* EventHistoryRequest.swift in Sources */,
3FB66AE324CA004400502CAF /* ConfigurationDownloadable.swift in Sources */,
Expand Down Expand Up @@ -3184,6 +3198,7 @@
3FB66AD024CA004400502CAF /* AEPError.swift in Sources */,
3FB66AD424CA004400502CAF /* EventType.swift in Sources */,
3F5D45F8251903030040E298 /* LaunchRuleTransformer.swift in Sources */,
7522618D2AABBE9600D59847 /* UserDefaultMigrationConstants.swift in Sources */,
24EDE33926F10BA10068A65F /* String+FNV1A32.swift in Sources */,
21A6737325434AE600A7E906 /* SharedStateType.swift in Sources */,
);
Expand All @@ -3206,6 +3221,7 @@
24B4BE5D2714F7B30000C3AA /* EventHistoryTests.swift in Sources */,
3F16762824F031A00041B970 /* EventHubContractTests.swift in Sources */,
BBE1295124DBCE870045CD8D /* TokenFinderTests.swift in Sources */,
7522618F2AAF6E2400D59847 /* UserDefaultMigratorTests.swift in Sources */,
3F5D45FB251904F00040E298 /* LaunchRuleTransformerTests.swift in Sources */,
3F39521624CA096200F7325B /* MockNetworkServiceOverrider.swift in Sources */,
3F16762A24F032C60041B970 /* ContractExtensionOne.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion AEPCore/Sources/core/MobileCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public final class MobileCore: NSObject {
let idParser = IDParser()
V4Migrator(idParser: idParser).migrate() // before starting SDK, migrate from v4 if needed
V5Migrator(idParser: idParser).migrate() // before starting SDK, migrate from v5 if needed

UserDefaultsMigrator().migrate() // before starting SDK, migrate from UserDefaults if needed
// Invoke registerExtension on legacy extensions
let legacyExtensions = extensions.filter {!($0.self is Extension.Type)} // All extensions that do not conform to `Extension`
let registerSelector = Selector(("registerExtension"))
Expand Down
191 changes: 191 additions & 0 deletions AEPCore/Sources/migration/UserDefaultMigrationConstants.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
//
/*
Copyright 2023 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

import Foundation

enum UserDefaultMigratorConstants {

static let MIGRATION_STORE_NAME = "com.adobe.migration"
static let MIGRATION_COMPLETE = "migration.userdefaults.complete"

static let migrationDict: [String: [String]] = [
Configuration.DATASTORE_NAME: Configuration.DataStoreKeys.allCases.map {$0.rawValue},
Identity.DATASTORE_NAME: Identity.DataStoreKeys.allCases.map {$0.rawValue},
Lifecycle.DATASTORE_NAME: Lifecycle.DataStoreKeys.allCases.map {$0.rawValue},
Assurance.DATASTORE_NAME: Assurance.DataStoreKeys.allCases.map {$0.rawValue},
Analytics.DATASTORE_NAME: Analytics.DataStoreKeys.allCases.map {$0.rawValue},
Audience.DATASTORE_NAME: Audience.DataStoreKeys.allCases.map {$0.rawValue},
Target.DATASTORE_NAME: Target.DataStoreKeys.allCases.map {$0.rawValue},
Campaign.DATASTORE_NAME: Campaign.DataStoreKeys.allCases.map {$0.rawValue},
CampaignClassic.DATASTORE_NAME: CampaignClassic.DataStoreKeys.allCases.map {$0.rawValue},
Places.DATASTORE_NAME: Places.DataStoreKeys.allCases.map {$0.rawValue},
UserProfile.DATASTORE_NAME: UserProfile.DataStoreKeys.allCases.map {$0.rawValue},
Edge.DATASTORE_NAME: Edge.EdgeDataStoreKeys.allCases.map {$0.rawValue},
Edge.PAYLOAD_DATASTORE_NAME: Edge.EdgePayloadStoreKeys.allCases.map {$0.rawValue},
EdgeIdentity.DATASTORE_NAME: EdgeIdentity.DataStoreKeys.allCases.map {$0.rawValue},
EdgeConsent.DATASTORE_NAME: EdgeConsent.DataStoreKeys.allCases.map {$0.rawValue}
]

enum Configuration {
static let DATASTORE_NAME = "com.adobe.module.configuration"

enum DataStoreKeys: String, CaseIterable {
case OVERRIDDEN_MAP = "config.overridden.map"
case APP_ID = "config.appID"
}
}

enum Lifecycle {
static let DATASTORE_NAME = "com.adobe.module.lifecycle"

enum DataStoreKeys: String, CaseIterable {
case INSTALL_DATE = "install.date"
case LAST_LAUNCH_DATE = "last.date.used"
case UPGRADE_DATE = "upgrade.date"
case LAUNCHES_SINCE_UPGRADE = "launches.after.upgrade"
case PERSISTED_CONTEXT = "persisted.context"
case LIFECYCLE_DATA = "lifecycle.data"
case LAST_VERSION = "last.version"
case V2_LAST_VERSION = "v2.last.app.version"
case V2_APP_START_DATE = "v2.app.start.date"
case V2_APP_PAUSE_DATE = "v2.app.pause.date"
case V2_APP_CLOSE_DATE = "v2.app.close.date"
}
}

enum Identity {
static let DATASTORE_NAME = "com.adobe.module.identity"

enum DataStoreKeys: String, CaseIterable {
case IDENTITY_PROPERTIES = "identity.properties"
case PUSH_ENABLED = "push.enabled"
case ANALYTICS_PUSH_ENABLED = "analytics.push.enabled"
}
}

enum Assurance {
static let DATASTORE_NAME = "com.adobe.module.assurance"

enum DataStoreKeys: String, CaseIterable {
case CLIENT_ID = "assurance.client.Id"
case ENVIRONMENT = "assurance.environment"
case SOCKET_URL = "assurance.socketurl"
case MODIFIED_CONFIG_KEYS = "assurance.control.modifiedConfigKeys"
}
}

enum Analytics {
static let DATASTORE_NAME = "com.adobe.module.analytics"

enum DataStoreKeys: String, CaseIterable {
case LAST_HIT_TS = "mostrecenthittimestamp"
case AID = "aid"
case VID = "vid"
case DATA_MIGRATED = "data.migrated"
}
}

enum Audience {
static let DATASTORE_NAME = "com.adobe.module.audience"

enum DataStoreKeys: String, CaseIterable {
case USER_PROFILE = "AAMUserProfile"
case USER_ID = "AAMUserId"
}
}

enum Target {
static let DATASTORE_NAME = "com.adobe.module.target"

enum DataStoreKeys: String, CaseIterable {
case SESSION_TIMESTAMP = "session.timestamp"
case SESSION_ID = "session.id"
case TNT_ID = "tnt.id"
case EDGE_HOST = "edge.host"
case THIRD_PARTY_ID = "thirdparty.id"
}
}

enum Campaign {
static let DATASTORE_NAME = "com.adobe.module.campaign"

enum DataStoreKeys: String, CaseIterable {
case REMOTE_URL = "CampaignRemoteUrl"
case ECID = "ExperienceCloudId"
case REGISTRATION_TS = "CampaignRegistrationTimestamp"
}
}

enum CampaignClassic {
static let DATASTORE_NAME = "com.adobe.module.campaignclassic"

enum DataStoreKeys: String, CaseIterable {
case TOKEN_HASH = "ADOBEMOBILE_STOREDDEFAULTS_TOKENHASH"
}
}

enum Places {
static let DATASTORE_NAME = "PlacesDataStore"

enum DataStoreKeys: String, CaseIterable {
case ACCURACY = "places_accuracy"
case AUTH_STATUS = "places_auth_status"
case CURRENT_POI = "places_current_poi"
case LAST_ENTERED_POI = "places_last_entered_poi"
case LAST_EXITED_POI = "places_last_exited_poi"
case LAST_KNOWN_LATITUDE = "places_last_known_latitude"
case LAST_KNOWN_LONGITUDE = "places_last_known_longitude"
case MEMBERSHIP = "places_membership_valid_until"
case NEARBY_POIS = "places_nearby_pois"
case USER_WITHIN_POIS = "places_user_within_pois"
}
}

enum UserProfile {
static let DATASTORE_NAME = "com.adobe.module.userProfile"

enum DataStoreKeys: String, CaseIterable {
case ATTRIBUTES = "attributes"
}
}

enum Edge {
static let DATASTORE_NAME = "com.adobe.edge"
static let PAYLOAD_DATASTORE_NAME = "AEPEdge"

enum EdgeDataStoreKeys: String, CaseIterable {
case RESET_IDENTITIES_DATE = "reset.identities.date"
case EDGE_PROPERTIES = "edge.properties"
}

enum EdgePayloadStoreKeys: String, CaseIterable {
case STORE_PAYLOADS = "storePayloads"
}
}

enum EdgeIdentity {
static let DATASTORE_NAME = "com.adobe.edge.identity"

enum DataStoreKeys: String, CaseIterable {
case IDENTITY_PROPERTIES = "identity.properties"
}
}

enum EdgeConsent {
static let DATASTORE_NAME = "com.adobe.edge.consent"

enum DataStoreKeys: String, CaseIterable {
case CONSENT_PREFERENCES = "consent.preferences"
}
}
}
67 changes: 67 additions & 0 deletions AEPCore/Sources/migration/UserDefaultsMigrator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
/*
Copyright 2023 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

import Foundation
import AEPServices

struct UserDefaultsMigrator {
private let LOG_TAG = "UserDefaultsMigrator"
private typealias constants = UserDefaultMigratorConstants
private let dataStore = ServiceProvider.shared.namedKeyValueService
private var defaults: UserDefaults {
if let appGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup() {
return UserDefaults(suiteName: appGroup) ?? UserDefaults.standard
}

return UserDefaults.standard
}

func migrate() {
if needToMigrate() {
Log.debug(label: LOG_TAG, "Beginning UserDefaults migration")
for (collectionName, keys) in constants.migrationDict {
for key in keys {
if let valueToMigrate = getAndDelete(key: keyWithPrefix(datastoreName: collectionName, key: key)) {
dataStore.set(collectionName: collectionName, key: key, value: valueToMigrate)
}
}
Log.debug(label: LOG_TAG, "UserDefaults Migration complete for \(collectionName)")
}
dataStore.set(collectionName: constants.MIGRATION_STORE_NAME, key: constants.MIGRATION_COMPLETE, value: true)
Log.debug(label: LOG_TAG, "UserDefaults migration complete")
}
}

private func needToMigrate() -> Bool {
guard let migrationComplete = dataStore.get(collectionName: constants.MIGRATION_STORE_NAME, key: constants.MIGRATION_COMPLETE) as? Bool else {
return true
}

return !migrationComplete

}

private func keyWithPrefix(datastoreName: String, key: String) -> String {
return "Adobe.\(datastoreName).\(key)"
}

private func getAndDelete(key: String) -> Any? {
guard let value = defaults.object(forKey: key) else {
Log.trace(label: LOG_TAG, "No value for \(key) found")
return nil
}

defaults.removeObject(forKey: key)
return value
}
}
Loading

0 comments on commit b431e5a

Please sign in to comment.